From 0249b5fc410b6c6814906b185dfdf25b27621148 Mon Sep 17 00:00:00 2001 From: pkranthi Date: Fri, 23 Feb 2024 16:43:25 +0530 Subject: [PATCH] RIC-997: ErrorIndication handling in e2mgr Change-Id: I355b1ca452d00ce461c306c0178c8aa5c498c5bc Signed-off-by: pkranthi --- E2Manager/app/main.go | 11 +- .../e2_setup_request_notification_handler.go | 10 + .../error_indication_notification_handler.go | 156 +++++++++++ .../error_indication_notification_handler_test.go | 294 +++++++++++++++++++++ .../rmrmsghandlers/ric_service_update_handler.go | 8 +- .../ric_service_update_handler_test.go | 4 +- .../notification_manager_test.go | 3 +- E2Manager/managers/ric_service_update_manager.go | 82 ++++++ .../managers/ric_service_update_manager_test.go | 71 +++++ E2Manager/mocks/logger_mock.go | 45 ++++ E2Manager/mocks/ricServiceUpdate_manager_mock.go | 32 +++ E2Manager/models/e2_error_indication_message.go | 93 +++++++ .../models/e2_error_indication_message_test.go | 32 +++ .../notification_handler_provider.go | 6 +- .../notification_handler_provider_test.go | 15 +- E2Manager/rmrCgo/rmrCgoApi.go | 4 + E2Manager/rmrCgo/rmrCgoTypes.go | 1 + E2Manager/rmrCgo/rmrCgoUtils.go | 3 + .../services/rmrreceiver/rmr_receiver_test.go | 3 +- .../errorIndication/errorIndicationForDefault.xml | 56 ++++ .../errorIndicationForServiceUpdate.xml | 56 ++++ .../errorIndicationForSetupRequest.xml | 56 ++++ .../errorIndication/errorIndicationInvalid.xml | 55 ++++ .../errorIndicationUnsuccessfulOutcome.xml | 56 ++++ .../errorIndication/errorIndicationWithoutCD.xml | 36 +++ 25 files changed, 1170 insertions(+), 18 deletions(-) create mode 100644 E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler.go create mode 100644 E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler_test.go create mode 100644 E2Manager/managers/ric_service_update_manager.go create mode 100644 E2Manager/managers/ric_service_update_manager_test.go create mode 100644 E2Manager/mocks/logger_mock.go create mode 100644 E2Manager/mocks/ricServiceUpdate_manager_mock.go create mode 100644 E2Manager/models/e2_error_indication_message.go create mode 100644 E2Manager/models/e2_error_indication_message_test.go create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationForDefault.xml create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationForServiceUpdate.xml create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationForSetupRequest.xml create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationInvalid.xml create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationUnsuccessfulOutcome.xml create mode 100644 E2Manager/tests/resources/errorIndication/errorIndicationWithoutCD.xml diff --git a/E2Manager/app/main.go b/E2Manager/app/main.go index 58d20b5..dc2ff87 100644 --- a/E2Manager/app/main.go +++ b/E2Manager/app/main.go @@ -35,12 +35,12 @@ import ( "e2mgr/services/rmrreceiver" "e2mgr/services/rmrsender" //"fmt" - "flag" + "flag" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" - "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" - "github.com/spf13/viper" - "github.com/fsnotify/fsnotify" + "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" + "github.com/spf13/viper" + "github.com/fsnotify/fsnotify" "os" "strconv" ) @@ -141,6 +141,7 @@ func main() { rnibDataService := services.NewRnibDataService(Log, config, reader.GetNewRNibReader(sdl), rNibWriter.GetRNibWriter(sdl, config.RnibWriter)) ranListManager := managers.NewRanListManager(Log, rnibDataService) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(Log, rnibDataService) err = ranListManager.InitNbIdentityMap() @@ -160,7 +161,7 @@ func main() { e2tShutdownManager := managers.NewE2TShutdownManager(Log, config, rnibDataService, e2tInstancesManager, e2tAssociationManager, ranConnectStatusChangeManager) e2tKeepAliveWorker := managers.NewE2TKeepAliveWorker(Log, rmrSender, e2tInstancesManager, e2tShutdownManager, config) rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() - rmrNotificationHandlerProvider.Init(Log, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) + rmrNotificationHandlerProvider.Init(Log, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager) notificationManager := notificationmanager.NewNotificationManager(Log, rmrNotificationHandlerProvider) rmrReceiver := rmrreceiver.NewRmrReceiver(Log, rmrMessenger, notificationManager) diff --git a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go index 9dde134..3f93c58 100644 --- a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go @@ -90,6 +90,7 @@ func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configu func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationRequest) { ranName := request.RanName + models.UpdateProcedureType(ranName, models.E2SetupProcedureNotInitiated) h.logger.Infof("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - received E2_SETUP_REQUEST. Payload: %x", ranName, request.Payload) generalConfiguration, err := h.rNibDataService.GetGeneralConfiguration() @@ -113,6 +114,7 @@ func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationR if !generalConfiguration.EnableRic { cause := models.Cause{Misc: &models.CauseMisc{OmIntervention: &struct{}{}}} h.handleUnsuccessfulResponse(ranName, request, cause, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureFailure) return } @@ -138,6 +140,7 @@ func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationR if _, ok := err.(*e2managererrors.UnknownSetupRequestRanNameError); ok { cause := models.Cause{RicRequest: &models.CauseRic{RequestIdUnknown: &struct{}{}}} h.handleUnsuccessfulResponse(ranName, request, cause, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureFailure) } return } @@ -148,9 +151,11 @@ func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationR if err != nil { h.fillCauseAndSendUnsuccessfulResponse(nodebInfo, request, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureFailure) return } } + models.UpdateProcedureType(ranName, models.E2SetupProcedureOngoing) ranStatusChangePublished, err := h.e2tAssociationManager.AssociateRan(e2tIpAddress, nodebInfo) @@ -165,6 +170,7 @@ func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationR cause := models.Cause{Transport: &models.CauseTransport{TransportResourceUnavailable: &struct{}{}}} h.handleUnsuccessfulResponse(nodebInfo.RanName, request, cause, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureFailure) } return } @@ -174,6 +180,8 @@ func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationR } h.handleSuccessfulResponse(ranName, request, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureCompleted) + h.logger.Debugf("#E2SetupRequestNotificationHandler.Handle - updating the enum value to e2setup request completed") } func (h *E2SetupRequestNotificationHandler) handleUpdateAndPublishNodebInfo(functionsModified bool, ranStatusChangePublished bool, nodebInfo *entities.NodebInfo) error { @@ -459,8 +467,10 @@ func (h *E2SetupRequestNotificationHandler) buildNbIdentity(ranName string, setu } func (h *E2SetupRequestNotificationHandler) fillCauseAndSendUnsuccessfulResponse(nodebInfo *entities.NodebInfo, request *models.NotificationRequest, setupRequest *models.E2SetupRequestMessage) { + ranName := request.RanName if nodebInfo.GetConnectionStatus() == entities.ConnectionStatus_DISCONNECTED { cause := models.Cause{Misc: &models.CauseMisc{ControlProcessingOverload: &struct{}{}}} h.handleUnsuccessfulResponse(nodebInfo.RanName, request, cause, setupRequest) + models.UpdateProcedureType(ranName, models.E2SetupProcedureFailure) } } diff --git a/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler.go new file mode 100644 index 0000000..321563f --- /dev/null +++ b/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler.go @@ -0,0 +1,156 @@ +// Copyright 2023 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 rmrmsghandlers + +import ( + "bytes" + "e2mgr/logger" + "e2mgr/managers" + "e2mgr/models" + "e2mgr/utils" + "encoding/xml" + "fmt" + + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "sync" +) + +var e2ErrorIndicationMessage = models.ErrorIndicationMessage{} + +var E2SETUP_PROCEDURE string = "1" +var RICSERVICEUPDATE_PROCEDURE string = "7" + +type ErrorIndicationHandler struct { + logger *logger.Logger + ranDisconnectionManager managers.IRanDisconnectionManager + RicServiceUpdateManager managers.IRicServiceUpdateManager + procedureMapMutex sync.RWMutex +} + + +func ErrorIndicationNotificationHandler(logger *logger.Logger, ranDisconnectionManager managers.IRanDisconnectionManager, RicServiceUpdateManager managers.IRicServiceUpdateManager) *ErrorIndicationHandler { + return &ErrorIndicationHandler{ + logger: logger, + ranDisconnectionManager: ranDisconnectionManager, + RicServiceUpdateManager: RicServiceUpdateManager, + } +} +func (errorIndicationHandler *ErrorIndicationHandler) Handle (request *models.NotificationRequest) { + ranName := request.RanName + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-Received Error Indication from E2Node - %s", ranName) + + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-Received ErrorIndication payload at E2M is - %x", request.Payload) + errorIndicationMessage, err := errorIndicationHandler.parseErrorIndication(request.Payload) + if err != nil { + errorIndicationHandler.logger.Errorf("#ErrorIndicationHandler.Handle- Parsing is not successful") + return + } + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle ERROR INDICATION from E2Node has been parsed successfully- %+v", errorIndicationMessage) + errorIndicationIE := errorIndicationMessage.E2APPDU.InitiatingMessage.Value.ErrorIndication.ProtocolIEs.ErrorIndicationIEs + fmt.Printf("errorIndicationIE value is %+v", errorIndicationIE) + + for i := 0 ; i < len(errorIndicationIE) ; i++ { + if errorIndicationIE[i].ID == 2 { + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-CD is: %+v", errorIndicationIE[i].Value.CriticalityDiagnostics) + if errorIndicationIE[i].Value.CriticalityDiagnostics.ProcedureCode != "" && errorIndicationIE[i].Value.CriticalityDiagnostics.TriggeringMessage.SuccessfulOutcome != nil { + procedureCode := errorIndicationIE[i].Value.CriticalityDiagnostics.ProcedureCode + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-procedureCode present is: %+v", procedureCode) + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle- before triggeringMessage present is: %+v", errorIndicationIE[i].Value.CriticalityDiagnostics.TriggeringMessage) + triggeringMessageValue := &errorIndicationIE[i].Value.CriticalityDiagnostics.TriggeringMessage.SuccessfulOutcome + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-triggeringMessage present is: %+v", *triggeringMessageValue) + if procedureCode != "" && triggeringMessageValue != nil { + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.handleErrorIndicationBasedOnProcedureCode for all scenarios") + switch procedureCode { + case E2SETUP_PROCEDURE: + if triggeringMessageValue != nil { + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication happened at E2Setup procedure") + err = errorIndicationHandler.ranDisconnectionManager.DisconnectRan(ranName) + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-Cleanup Completed !!") + return + } else { + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication recieved for unsuccessful-outcome, no action taken") + } + case RICSERVICEUPDATE_PROCEDURE: + if triggeringMessageValue != nil { + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication happened at Ric Service Update procedure") + err = errorIndicationHandler.RicServiceUpdateManager.RevertRanFunctions(ranName) + if err != nil { + errorIndicationHandler.logger.Errorf("#ErrorIndicationHandler.Handle-reverting RanFunctions and updating the nodebInfo failed due to error %+v", err) + } + return + } else { + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication recieved for unsuccessful-outcome, no action taken") + } + default: + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-problem in handling of error indication") + return + } + } + } + } + } + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-CriticalityDiagnostics IEs unsuccessful hence Retrieving based on procedureMap") + errorIndicationHandler.HandleBasedOnProcedureType(ranName) + errorIndicationHandler.logger.Debugf("#ErrorIndicationHandler.Handle-Cleanup Completed !!") +} + + + +func (errorIndicationHandler *ErrorIndicationHandler) HandleBasedOnProcedureType(ranName string) error { + errorIndicationHandler.procedureMapMutex.RLock() + procedureType, ok := models.ProcedureMap[ranName] + errorIndicationHandler.procedureMapMutex.RUnlock() + if !ok { + errorIndicationHandler.logger.Errorf("#ErrorIndicationHandler.Handle-Error ProcedureType not found for ranName %s", ranName) + } else { + switch procedureType { + case models.E2SetupProcedureCompleted: + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication happened at E2Setup procedure") + err := errorIndicationHandler.ranDisconnectionManager.DisconnectRan(ranName) + if err != nil { + errorIndicationHandler.logger.Errorf("#ErrorIndicationHandler.Handle-Disconnect RAN and updating the nodebInfo failed due to error %+v", err) + } + case models.RicServiceUpdateCompleted: + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication happened at Ric Service Update procedure") + err := errorIndicationHandler.RicServiceUpdateManager.RevertRanFunctions(ranName) + if err != nil { + errorIndicationHandler.logger.Errorf("#ErrorIndicationHandler.Handle-reverting RanFunctions and updating the nodebInfo failed due to error %+v", err) + } + case models.E2SetupProcedureFailure, models.RicServiceUpdateFailure: + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-ErrorIndication occcured before successful outcome hence ignoring") + default: + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.Handle-Error in handling the ErrorIndication based on enum") + } + } + return nil +} + +func (errorIndicationHandler *ErrorIndicationHandler) parseErrorIndication(payload []byte) (*models.ErrorIndicationMessage, error) { + pipInd := bytes.IndexByte(payload, '|') + if pipInd < 0 { + return nil, common.NewInternalError(fmt.Errorf("#ErrorIndicationHandler.parseErrorIndication - Error parsing ERROR INDICATION failed extract Payload: no | separator found")) + } + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.parseErrorIndication - payload: %s", payload) + errorIndicationHandler.logger.Infof("#ErrorIndicationHandler.parseErrorIndication - payload: %s", payload[pipInd+1:]) + errorIndicationMessage := &models.ErrorIndicationMessage{} + err := xml.Unmarshal(utils.NormalizeXml(payload[pipInd+1:]), &errorIndicationMessage.E2APPDU) + if err != nil { + return nil, common.NewInternalError(fmt.Errorf("#ErrorIndicationHandler.parseErrorIndication - Error unmarshalling ERROR INDICATION payload: %x", payload)) + } + return errorIndicationMessage, nil +} \ No newline at end of file diff --git a/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler_test.go new file mode 100644 index 0000000..af3e578 --- /dev/null +++ b/E2Manager/handlers/rmrmsghandlers/error_indication_notification_handler_test.go @@ -0,0 +1,294 @@ +// Copyright 2023 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 rmrmsghandlers + +import ( + "bytes" + "e2mgr/clients" + "e2mgr/configuration" + "e2mgr/managers" + "e2mgr/mocks" + "e2mgr/models" + "e2mgr/tests" + "e2mgr/services" + "e2mgr/utils" + "encoding/json" + "io/ioutil" + "net/http" + "testing" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const ( + RanNameForErrorIndication = "test" + E2tAddress = "10.10.2.15:9800" + e2tInstanceFullAddressErrorIndication = "10.0.2.15:9999" + e2SetupMsgPrefixErrorIndication = e2tInstanceFullAddressErrorIndication + "|" + ErrorIndicationXmlPath = "../../tests/resources/errorIndication/ErrorIndicationForSetupRequest.xml" + ErrorIndicationWithoutCDXmlPath = "../../tests/resources/errorIndication/ErrorIndicationWithoutCD.xml" + ErrorIndicationXmlPathServiceUpdate = "../../tests/resources/errorIndication/ErrorIndicationForServiceUpdate.xml" + ErrorIndicationXmlPathUnsuccessfuOutcome = "../../tests/resources/errorIndication/ErrorIndicationUnsuccessfulOutcome.xml" + ErrorIndicationXmlPathDefault = "../../tests/resources/errorIndication/ErrorIndicationForDefault.xml" + ErrorIndicationInvalidXmlPath = "../../tests/resources/errorIndication/ErrorIndicationInvalid.xml" +) + +func initErrorIndication(t *testing.T) (*ErrorIndicationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock, *mocks.RoutingManagerClientMock, managers.RanListManager,*mocks.RanDisconnectionManagerMock,*mocks.RicServiceUpdateManagerMock, *mocks.MockLogger, *mocks.HttpClientMock,*mocks.RanListManagerMock) { + logger := tests.InitLog(t) + config := &configuration.Configuration{ + RnibRetryIntervalMs: 10, + MaxRnibConnectionAttempts: 3, + RnibWriter: configuration.RnibWriterConfig{ + StateChangeMessageChannel: StateChangeMessageChannel, + }, + GlobalRicId: struct { + RicId string + Mcc string + Mnc string + }{Mcc: "327", Mnc: "94", RicId: "AACCE"}} + rmrMessengerMock := &mocks.RmrMessengerMock{} + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + RanDisconnectionManagerMock := &mocks.RanDisconnectionManagerMock{} + ricServiceUpdateManagerMock := &mocks.RicServiceUpdateManagerMock{} + MockLogger := &mocks.MockLogger{} + routingManagerClientMock := &mocks.RoutingManagerClientMock{} + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} + httpClientMock := &mocks.HttpClientMock{} + ranListManagerMock := &mocks.RanListManagerMock{} + + ranListManager := managers.NewRanListManager(logger, rnibDataService) + ranAlarmService := services.NewRanAlarmService(logger, config) + ranConnectStatusChangeManager := managers.NewRanConnectStatusChangeManager(logger, rnibDataService, ranListManager, ranAlarmService) + e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManagerMock, routingManagerClientMock, ranConnectStatusChangeManager) + ranDisconnectionManager := managers.NewRanDisconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, e2tAssociationManager, ranConnectStatusChangeManager) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) + handler := ErrorIndicationNotificationHandler(logger, ranDisconnectionManager, RicServiceUpdateManager) + + return handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock, ranListManager, RanDisconnectionManagerMock, ricServiceUpdateManagerMock,MockLogger,httpClientMock,ranListManagerMock +} + +func TestParseErrorIndicationMessage_Success(t *testing.T) { + ErrorgnbXml := utils.ReadXmlFile(t, ErrorIndicationXmlPath) + handler, _, _, _, _, _, _, _, _,_,_,_ := initErrorIndication(t) + prefBytes := []byte(e2SetupMsgPrefixErrorIndication) + errorIndicationMessage, err := handler.parseErrorIndication(append(prefBytes, ErrorgnbXml...)) + assert.NotNil(t, errorIndicationMessage) + assert.Nil(t, err) +} + +func TestParseErrorIndication_PipFailure(t *testing.T) { + ErrorgnbXml := utils.ReadXmlFile(t, ErrorIndicationXmlPath) + handler, _, _, _, _, _,_ ,_, _, _,_,_ := initErrorIndication(t) + prefBytes := []byte("10.0.2.15:9999") + request, err := handler.parseErrorIndication(append(prefBytes, ErrorgnbXml...)) + assert.Nil(t, request) + assert.NotNil(t, err) + assert.EqualError(t, err, "#ErrorIndicationHandler.parseErrorIndication - Error parsing ERROR INDICATION failed extract Payload: no | separator found") +} +func TestParseErrorIndicationMessage_UnmarshalFailure(t *testing.T) { + handler, _,_, _, _, _, _, _, _, _,_,_ := initErrorIndication(t) + prefBytes := []byte(e2SetupMsgPrefixErrorIndication) + errorIndicationMessage, err := handler.parseErrorIndication(append(prefBytes, 1, 2, 3)) + assert.Nil(t, errorIndicationMessage) + assert.NotNil(t, err) + assert.EqualError(t, err, "#ErrorIndicationHandler.parseErrorIndication - Error unmarshalling ERROR INDICATION payload: 31302e302e322e31353a393939397c010203") +} + +func testErrorIndicationNotificationHandler(t *testing.T) { + handler, readerMock, writerMock, _, _, _, _, _, _,_ ,_,_:= initErrorIndication(t) + writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil) + notificationRequest := models.NotificationRequest{RanName: RanNameForErrorIndication} + handler.Handle(¬ificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) +} + +func testErrorIndicationHandlerWhenConnectedRanSuccess(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, e2tInstancesManagerMock,routingManagerClientMock, _, _, _, _,httpClientMock,_ := initErrorIndication(t) + origNodebInfo := &entities.NodebInfo{ + RanName: RanNameForErrorIndication, + GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, + ConnectionStatus: entities.ConnectionStatus_CONNECTED, + AssociatedE2TInstanceAddress: E2tAddress, + } + + models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureCompleted) + var rnibErr error + readerMock.On("GetNodeb", RanNameForErrorIndication).Return(origNodebInfo, rnibErr) + updatedNodebInfo1 := *origNodebInfo + updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanNameForErrorIndication+"_DISCONNECTED").Return(rnibErr) + updatedNodebInfo2 := *origNodebInfo + updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + updatedNodebInfo2.AssociatedE2TInstanceAddress = "" + writerMock.On("UpdateNodebInfo", mock.Anything).Return(rnibErr) + e2tInstance := &entities.E2TInstance{Address: E2tAddress, AssociatedRanList: []string{RanNameForErrorIndication}} + readerMock.On("GetE2TInstance", E2tAddress).Return(e2tInstance, nil).Maybe() + e2tInstanceToSave := *e2tInstance + e2tInstanceToSave.AssociatedRanList = []string{} + //writerMock.On("SaveE2TInstance", &e2tInstanceToSave).Return(nil) + mockHttpClientForErrorIndication(httpClientMock, true) //After uncommenting testcase is failing + e2tInstancesManagerMock.On("RemoveRanFromInstance", RanNameForErrorIndication, E2tAddress).Return(nil) + routingManagerClientMock.On("DissociateRanE2TInstance", E2tAddress, RanNameForErrorIndication).Return(nil) + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + + + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) + httpClientMock.AssertExpectations(t) + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) +} +func TestErrorIndicationHandlerWhenConnectedGnbSuccessE2Setup(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationXmlPath) +} + +func TestErrorIndicationHandlerWhenConnectedGnbSuccessProcedureType(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationWithoutCDXmlPath) +} +func TestErrorIndicationHandlerWhenConnectedGnbSuccessServiceUpdate(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t, ErrorIndicationXmlPathServiceUpdate) +} +func TestErrorIndicationHandlerWhenConnectedGnbSuccessServiceUpdateProcedureType(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t, ErrorIndicationWithoutCDXmlPath) +} +func TestErrorIndicationHandlerWhenConnectedGnbSuccessUnsuccessfulOutcome(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationXmlPathUnsuccessfuOutcome) +} +func TestErrorIndicationHandlerInvalidXML(t *testing.T) { + testErrorIndicationHandlerInvalidXML(t, ErrorIndicationInvalidXmlPath) +} +func TestErrorIndicationHandlerForUnknownProcedureType(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccessUnknownProcedureType(t,ErrorIndicationWithoutCDXmlPath) +} +func TestErrorIndicationHandlerForUnhandlingProcedureType(t *testing.T) { + testErrorIndicationHandlerWhenConnectedRanSuccessUnhandlingProcedureType(t,ErrorIndicationWithoutCDXmlPath) +} +func TestErrorIndicationHandlerForDefaultProcedureCode(t *testing.T) { + testErrorIndicationHandlerForDefaultProcedureCode(t,ErrorIndicationXmlPathDefault) +} +func mockHttpClientForErrorIndication(httpClientMock *mocks.HttpClientMock, isSuccessful bool) { + data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2tAddress, RanNameForErrorIndication)} + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + var respStatusCode int + if isSuccessful { + respStatusCode = http.StatusCreated + } else { + respStatusCode = http.StatusBadRequest + } + httpClientMock.On("Post", clients.DissociateRanE2TInstanceApiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil).Maybe() +} + +func testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, _,_, _, _, _, _,_,_ := initErrorIndication(t) + origNodebInfo := &entities.NodebInfo{ + RanName: RanNameForErrorIndication, + GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, + ConnectionStatus: entities.ConnectionStatus_CONNECTED, + AssociatedE2TInstanceAddress: E2tAddress, + } + logger := tests.InitLog(t) + config := &configuration.Configuration{ + RnibRetryIntervalMs: 10, + MaxRnibConnectionAttempts: 3, + RnibWriter: configuration.RnibWriterConfig{ + StateChangeMessageChannel: StateChangeMessageChannel, + }, + GlobalRicId: struct { + RicId string + Mcc string + Mnc string + }{Mcc: "327", Mnc: "94", RicId: "AACCE"}} + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) + models.UpdateProcedureType(RanNameForErrorIndication,models.RicServiceUpdateCompleted) + + var rnibErr error + readerMock.On("GetNodeb", RanNameForErrorIndication).Return(origNodebInfo, rnibErr) + updatedNodebInfo1 := *origNodebInfo + updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_CONNECTED + updatedNodebInfo2 := *origNodebInfo + updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_CONNECTED + updatedNodebInfo2.AssociatedE2TInstanceAddress = "" + e2tInstance := &entities.E2TInstance{Address: E2tAddress, AssociatedRanList: []string{RanNameForErrorIndication}} + readerMock.On("GetE2TInstance", E2tAddress).Return(e2tInstance, nil).Maybe() + e2tInstanceToSave := *e2tInstance + e2tInstanceToSave.AssociatedRanList = []string{} + writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil) + err := RicServiceUpdateManager.RevertRanFunctions(ranName) + assert.Nil(t,err) + + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) +} +func testErrorIndicationHandlerWhenConnectedRanSuccessUnknownProcedureType(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t) + + models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureNotInitiated) + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) + httpClientMock.AssertExpectations(t) +} + +func testErrorIndicationHandlerWhenConnectedRanSuccessUnhandlingProcedureType(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t) + + models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureFailure) + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) + httpClientMock.AssertExpectations(t) +} + +func testErrorIndicationHandlerInvalidXML(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t) + + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) + httpClientMock.AssertExpectations(t) +} +func testErrorIndicationHandlerForDefaultProcedureCode(t *testing.T,xmlPath string) { + xml := utils.ReadXmlFile(t, xmlPath) + handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t) + + notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)} + + handler.Handle(notificationRequest) + readerMock.AssertExpectations(t) + writerMock.AssertExpectations(t) + httpClientMock.AssertExpectations(t) +} diff --git a/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler.go b/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler.go index 15f89a8..b8d1c06 100644 --- a/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler.go @@ -55,14 +55,16 @@ type RicServiceUpdateHandler struct { rmrSender *rmrsender.RmrSender rNibDataService services.RNibDataService ranListManager managers.RanListManager + RicServiceUpdateManager managers.IRicServiceUpdateManager } -func NewRicServiceUpdateHandler(logger *logger.Logger, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, ranListManager managers.RanListManager) *RicServiceUpdateHandler { +func NewRicServiceUpdateHandler(logger *logger.Logger, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, ranListManager managers.RanListManager,RicServiceUpdateManager managers.IRicServiceUpdateManager) *RicServiceUpdateHandler { return &RicServiceUpdateHandler{ logger: logger, rmrSender: rmrSender, rNibDataService: rNibDataService, ranListManager: ranListManager, + RicServiceUpdateManager: RicServiceUpdateManager, } } @@ -87,6 +89,8 @@ func (h *RicServiceUpdateHandler) Handle(request *models.NotificationRequest) { return } h.logger.Infof("#RicServiceUpdateHandler.Handle - RIC_SERVICE_UPDATE has been parsed successfully %+v", ricServiceUpdate) + h.RicServiceUpdateManager.StoreExistingRanFunctions(ranName) + h.logger.Infof("#RicServiceUpdate.Handle - Getting the ranFunctions before we do the RIC ServiceUpdate handling") ackFunctionIds := h.updateFunctions(ricServiceUpdate.E2APPDU.InitiatingMessage.Value.RICServiceUpdate.ProtocolIEs.RICServiceUpdateIEs, nodebInfo) if len(ricServiceUpdate.E2APPDU.InitiatingMessage.Value.RICServiceUpdate.ProtocolIEs.RICServiceUpdateIEs) > 1 { @@ -112,6 +116,8 @@ func (h *RicServiceUpdateHandler) Handle(request *models.NotificationRequest) { } h.logger.Infof("#RicServiceUpdate.Handle - Completed successfully") + models.UpdateProcedureType(ranName, models.RicServiceUpdateCompleted) + h.logger.Debugf("#RicServiceUpdateHandler.Handle - updating the enum value to RicServiceUpdateCompleted completed") } func (h *RicServiceUpdateHandler) sendUpdateAck(updateAck models.RicServiceUpdateAckE2APPDU, nodebInfo *entities.NodebInfo, request *models.NotificationRequest) error { diff --git a/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler_test.go b/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler_test.go index 6e36298..2262d80 100644 --- a/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/ric_service_update_handler_test.go @@ -35,6 +35,7 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "e2mgr/managers" ) const ( @@ -77,7 +78,8 @@ func initRicServiceUpdateHandler(t *testing.T) (*RicServiceUpdateHandler, *mocks writerMock := &mocks.RnibWriterMock{} rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) ranListManagerMock := &mocks.RanListManagerMock{} - handler := NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManagerMock) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) + handler := NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManagerMock, RicServiceUpdateManager) return handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock } diff --git a/E2Manager/managers/notificationmanager/notification_manager_test.go b/E2Manager/managers/notificationmanager/notification_manager_test.go index 4ca6ce9..e1dfee0 100644 --- a/E2Manager/managers/notificationmanager/notification_manager_test.go +++ b/E2Manager/managers/notificationmanager/notification_manager_test.go @@ -50,10 +50,11 @@ func initNotificationManagerTest(t *testing.T) (*logger.Logger, *mocks.RnibReade routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) ranListManager := managers.NewRanListManager(logger, rnibDataService) ranAlarmService := services.NewRanAlarmService(logger, config) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) ranConnectStatusChangeManager := managers.NewRanConnectStatusChangeManager(logger, rnibDataService,ranListManager, ranAlarmService) e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManager, routingManagerClient, ranConnectStatusChangeManager) rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() - rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager,routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) + rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager,routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager) notificationManager := NewNotificationManager(logger, rmrNotificationHandlerProvider ) return logger, readerMock, notificationManager } diff --git a/E2Manager/managers/ric_service_update_manager.go b/E2Manager/managers/ric_service_update_manager.go new file mode 100644 index 0000000..c342e25 --- /dev/null +++ b/E2Manager/managers/ric_service_update_manager.go @@ -0,0 +1,82 @@ +// +// Copyright 2023 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" + "errors" + "e2mgr/models" +) + + +type IRicServiceUpdateManager interface { + RevertRanFunctions(ranName string) error + StoreExistingRanFunctions(ranName string) error +} + + +type RicServiceUpdateManager struct { + logger *logger.Logger + rNibDataService services.RNibDataService +} + +func NewRicServiceUpdateManager(logger *logger.Logger, rNibDataService services.RNibDataService) *RicServiceUpdateManager { + return &RicServiceUpdateManager{ + logger: logger, + rNibDataService: rNibDataService, + } +} + + +func (h *RicServiceUpdateManager) StoreExistingRanFunctions(ranName string) error { + nodebInfo, err := h.rNibDataService.GetNodeb(ranName) + if err != nil { + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions - failed to get nodeB entity for ran name: %v due to RNIB Error: %s", ranName, err) + } + if nodebInfo.GetGnb() == nil { + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions - GNB is nil for RAN name: %s", ranName) + return errors.New("There is empty gnb nodebInfo") + } + models.ExistingRanFunctiuonsMap[ranName] = nodebInfo.GetGnb().RanFunctions + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions - Updated ranFunctions for reverting the changes are %v:", models.ExistingRanFunctiuonsMap[ranName]) + return nil +} + +func (h *RicServiceUpdateManager) RevertRanFunctions(ranName string) error { + nodebInfo, err := h.rNibDataService.GetNodeb(ranName) + if err != nil { + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions - failed to get nodeB entity for ran name: %v due to RNIB Error: %s", ranName, err) + } + + if nodebInfo.GetGnb() != nil && nodebInfo.GetGnb().RanFunctions != nil { + nodebInfo.GetGnb().RanFunctions = models.ExistingRanFunctiuonsMap[ranName] + } else { + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions returned nil") + } + err = h.rNibDataService.UpdateNodebInfoAndPublish(nodebInfo) + if err != nil { + h.logger.Errorf("#RicServiceUpdateManager.revertRanFunctions - RAN name: %s - Failed at UpdateNodebInfoAndPublish. error: %s", nodebInfo.RanName, err) + return err + } + + h.logger.Infof("#RicServiceUpdateManager.revertRanFunctions - Revert ranFunctions for RAN name: %s", ranName) + return nil +} \ No newline at end of file diff --git a/E2Manager/managers/ric_service_update_manager_test.go b/E2Manager/managers/ric_service_update_manager_test.go new file mode 100644 index 0000000..b19e46e --- /dev/null +++ b/E2Manager/managers/ric_service_update_manager_test.go @@ -0,0 +1,71 @@ +// +// Copyright 2023 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/entities" + "testing" + "github.com/stretchr/testify/assert" + "e2mgr/tests" + "github.com/stretchr/testify/mock" +) + +const ( + serviceUpdateRANName1 = "gnb:TestRan1" + E2tAddress = "10.10.2.15:9800" +) + + +func initRicServiceUpdateManagerTest(t *testing.T) (*logger.Logger,*mocks.RnibReaderMock, *mocks.RnibWriterMock,services.RNibDataService, *configuration.Configuration, *RicServiceUpdateManager) { + logger := tests.InitLog(t) + + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + RicServiceUpdateManager := NewRicServiceUpdateManager(logger, rnibDataService) + return logger, readerMock, writerMock, rnibDataService, config, RicServiceUpdateManager +} +func TestUpdateRevertRanFunctions(t *testing.T) { + + _,readerMock, writerMock, _, _, RicServiceUpdateManager := initRicServiceUpdateManagerTest(t) + InvName := "test" + nodebInfo := &entities.NodebInfo{ + RanName: InvName, + NodeType: entities.Node_GNB, + Configuration: &entities.NodebInfo_Gnb{Gnb: &entities.Gnb{}}, + } + gnb := nodebInfo.GetGnb() + gnb.RanFunctions = []*entities.RanFunction{{RanFunctionId: 2, RanFunctionRevision: 2}} + readerMock.On("GetNodeb", InvName).Return(nodebInfo, nil) + writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil) + err := RicServiceUpdateManager.StoreExistingRanFunctions(ranName) + assert.Nil(t, err) + err = RicServiceUpdateManager.RevertRanFunctions(ranName) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + readerMock.AssertExpectations(t) + readerMock.AssertCalled(t, "GetNodeb", InvName) +} diff --git a/E2Manager/mocks/logger_mock.go b/E2Manager/mocks/logger_mock.go new file mode 100644 index 0000000..a5563cf --- /dev/null +++ b/E2Manager/mocks/logger_mock.go @@ -0,0 +1,45 @@ +// +// Copyright 2023 Nokia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package mocks + +import ( + "github.com/stretchr/testify/mock" +) + + +type MockLogger struct { + mock.Mock +} + +type MockRanDisconnectionManager struct { + mock.Mock +} + +type MockRicServiceUpdateManager struct { + mock.Mock +} + +func (m *MockLogger) Errorf(format string, args ...interface{}) { + m.Called(format, args) +} + +func (m *MockLogger) Infof(format string, args ...interface{}) { + m.Called(format, args) +} + diff --git a/E2Manager/mocks/ricServiceUpdate_manager_mock.go b/E2Manager/mocks/ricServiceUpdate_manager_mock.go new file mode 100644 index 0000000..ed3d493 --- /dev/null +++ b/E2Manager/mocks/ricServiceUpdate_manager_mock.go @@ -0,0 +1,32 @@ +// +// Copyright 2023 Nokia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package mocks + +import ( + "github.com/stretchr/testify/mock" +) + + +type RicServiceUpdateManagerMock struct { + mock.Mock +} + +func (m *RicServiceUpdateManagerMock) RevertRanFunctions(ranName string) error { + args := m.Called(ranName) + return args.Error(0) +} diff --git a/E2Manager/models/e2_error_indication_message.go b/E2Manager/models/e2_error_indication_message.go new file mode 100644 index 0000000..270c3e5 --- /dev/null +++ b/E2Manager/models/e2_error_indication_message.go @@ -0,0 +1,93 @@ +package models + +import ( + "encoding/xml" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "sync" + +) + + +type ProcedureType int + +const ( + E2SetupProcedureNotInitiated ProcedureType = iota + E2SetupProcedureOngoing + E2SetupProcedureCompleted + E2SetupProcedureFailure + RicServiceUpdateCompleted + RicServiceUpdateFailure +) + +var( + ProcedureMap = make(map[string]ProcedureType) + procedureMapMutex sync.RWMutex +) + +func UpdateProcedureType(ranName string, newProcedureType ProcedureType) { + procedureMapMutex.Lock() + defer procedureMapMutex.Unlock() + ProcedureMap[ranName] = newProcedureType +} + +var ExistingRanFunctiuonsMap = make(map[string][]*entities.RanFunction) + +type ErrorIndicationMessage struct { + XMLName xml.Name `xml:"ErrorIndicationMessage"` + Text string `xml:",chardata"` + E2APPDU ErrorIndicationE2APPDU `xml:"E2AP-PDU"` +} +type ErrorIndicationE2APPDU struct { + XMLName xml.Name `xml:"E2AP-PDU"` + Text string `xml:",chardata"` + InitiatingMessage ErrorIndicationInitiatingMessage `xml:"initiatingMessage"` +} +type ErrorIndicationInitiatingMessage struct { + Text string `xml:",chardata"` + ProcedureCode string `xml:"procedureCode"` + Criticality struct { + Text string `xml:",chardata"` + Reject string `xml:"reject"` + } `xml:"criticality"` + Value struct { + Text string `xml:",chardata"` + ErrorIndication struct { + Text string `xml:",chardata"` + ProtocolIEs struct { + Text string `xml:",chardata"` + ErrorIndicationIEs []ErrorIndicationIEs `xml:"ErrorIndication-IEs"` + } `xml:"protocolIEs"` + } `xml:"ErrorIndication"` + } `xml:"value"` +} +type ErrorIndicationIEs struct { + Text string `xml:",chardata"` + ID int `xml:"id"` + Criticality struct { + Text string `xml:",chardata"` + Reject string `xml:"reject"` + } `xml:"criticality"` + Value struct { + Text string `xml:",chardata"` + TransactionID string `xml:"TransactionID"` + RICrequestID struct { + Text string `xml:",chardata"` + RicRequestorID int32 `xml:"ricRequestorID"` + RicInstanceID int32 `xml:"ricInstanceID"` + } `xml:"RICrequestID"` + RANfunctionID int32 `xml:"RANfunctionID"` + CriticalityDiagnostics struct { + Text string `xml:",chardata"` + ProcedureCode string `xml:"procedureCode"` + TriggeringMessage TriggeringMessage `xml:"triggeringMessage"` + } `xml:"CriticalityDiagnostics"` + }`xml:"value"` +} + +type TriggeringMessage struct { + Text string `xml:",chardata"` + InitiatingMessage *struct{} `xml:"initiatingMessage"` + SuccessfulOutcome *struct{} `xml:"successful-outcome"` + UnsuccessfulOutcome *struct{} `xml:"unsuccessful-outcome"` +} + diff --git a/E2Manager/models/e2_error_indication_message_test.go b/E2Manager/models/e2_error_indication_message_test.go new file mode 100644 index 0000000..80b2159 --- /dev/null +++ b/E2Manager/models/e2_error_indication_message_test.go @@ -0,0 +1,32 @@ +// +// Copyright 2023 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_test + +import ( + "fmt" + "testing" + "e2mgr/models" + +) +const RanNameForErrorIndication = "test" + +func TestProcedureTypeForErrorIndication(t *testing.T) { + models.ProcedureMap[RanNameForErrorIndication] = models.E2SetupProcedureCompleted + models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureCompleted) + fmt.Println("updating the map to E2SetupProcedureCompleted") +} diff --git a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go index acdd956..fe17e75 100644 --- a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go +++ b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go @@ -61,7 +61,7 @@ func (provider *NotificationHandlerProvider) Register(msgType int, handler rmrms func (provider *NotificationHandlerProvider) Init(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, e2tInstancesManager managers.IE2TInstancesManager, routingManagerClient clients.IRoutingManagerClient, e2tAssociationManager *managers.E2TAssociationManager, - ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager, ranListManager managers.RanListManager) { + ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager, ranListManager managers.RanListManager,RicServiceUpdateManager managers.IRicServiceUpdateManager) { // Init converters x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) @@ -95,9 +95,10 @@ func (provider *NotificationHandlerProvider) Init(logger *logger.Logger, config e2TermInitNotificationHandler := rmrmsghandlers.NewE2TermInitNotificationHandler(logger, ranReconnectionManager, e2tInstancesManager, routingManagerClient) e2TKeepAliveResponseHandler := rmrmsghandlers.NewE2TKeepAliveResponseHandler(logger, rnibDataService, e2tInstancesManager) e2SetupRequestNotificationHandler := rmrmsghandlers.NewE2SetupRequestNotificationHandler(logger, config, e2tInstancesManager, rmrSender, rnibDataService, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) - ricServiceUpdateHandler := rmrmsghandlers.NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManager) + ricServiceUpdateHandler := rmrmsghandlers.NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManager, RicServiceUpdateManager) ricE2nodeConfigUpdateHandler := rmrmsghandlers.NewE2nodeConfigUpdateNotificationHandler(logger, rnibDataService, rmrSender) e2ResetRequestNotificationHandler := rmrmsghandlers.NewE2ResetRequestNotificationHandler(logger, rnibDataService, config, rmrSender, ranResetChangeManager, changeStatusToConnectedRanManager) + errorIndicationNotificationHandler := rmrmsghandlers.ErrorIndicationNotificationHandler(logger, ranReconnectionManager, RicServiceUpdateManager) provider.Register(rmrCgo.RIC_X2_SETUP_RESP, x2SetupResponseHandler) provider.Register(rmrCgo.RIC_X2_SETUP_FAILURE, x2SetupFailureResponseHandler) @@ -115,4 +116,5 @@ func (provider *NotificationHandlerProvider) Init(logger *logger.Logger, config provider.Register(rmrCgo.RIC_SERVICE_UPDATE, ricServiceUpdateHandler) provider.Register(rmrCgo.RIC_E2NODE_CONFIG_UPDATE, ricE2nodeConfigUpdateHandler) provider.Register(rmrCgo.RIC_E2_RESET_REQ, e2ResetRequestNotificationHandler) + provider.Register(rmrCgo.RIC_E2_RIC_ERROR_INDICATION, errorIndicationNotificationHandler) } diff --git a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go index 735bc1a..67ff5d2 100644 --- a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go +++ b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go @@ -42,7 +42,7 @@ import ( * Verify support for known providers. */ -func initTestCase(t *testing.T) (*logger.Logger, *configuration.Configuration, services.RNibDataService, *rmrsender.RmrSender, managers.IE2TInstancesManager, clients.IRoutingManagerClient, *managers.E2TAssociationManager, managers.IRanConnectStatusChangeManager, managers.RanListManager) { +func initTestCase(t *testing.T) (*logger.Logger, *configuration.Configuration, services.RNibDataService, *rmrsender.RmrSender, managers.IE2TInstancesManager, clients.IRoutingManagerClient, *managers.E2TAssociationManager, managers.IRanConnectStatusChangeManager, managers.RanListManager, managers.IRicServiceUpdateManager) { logger := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, RnibWriter: configuration.RnibWriterConfig{StateChangeMessageChannel: "RAN_CONNECTION_STATUS_CHANGE", RanManipulationMessageChannel: "RAN_MANIPULATION"}} @@ -56,14 +56,15 @@ func initTestCase(t *testing.T) (*logger.Logger, *configuration.Configuration, s routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) ranListManager := managers.NewRanListManager(logger, rnibDataService) ranAlarmService := services.NewRanAlarmService(logger, config) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) ranConnectStatusChangeManager := managers.NewRanConnectStatusChangeManager(logger, rnibDataService, ranListManager, ranAlarmService) e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManager, routingManagerClient, ranConnectStatusChangeManager) - return logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager + return logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager } func TestGetNotificationHandlerSuccess(t *testing.T) { - logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager := initTestCase(t) + logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager := initTestCase(t) ranDisconnectionManager := managers.NewRanDisconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, e2tAssociationManager, ranConnectStatusChangeManager) ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) @@ -98,7 +99,7 @@ func TestGetNotificationHandlerSuccess(t *testing.T) { {rmrCgo.E2_TERM_KEEP_ALIVE_RESP, rmrmsghandlers.NewE2TKeepAliveResponseHandler(logger, rnibDataService, e2tInstancesManager)}, {rmrCgo.RIC_X2_RESET_RESP, rmrmsghandlers.NewX2ResetResponseHandler(logger, rnibDataService, ranStatusChangeManager, converters.NewX2ResetResponseExtractor(logger))}, {rmrCgo.RIC_X2_RESET, rmrmsghandlers.NewX2ResetRequestNotificationHandler(logger, rnibDataService, ranStatusChangeManager, rmrSender)}, - {rmrCgo.RIC_SERVICE_UPDATE, rmrmsghandlers.NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManager)}, + {rmrCgo.RIC_SERVICE_UPDATE, rmrmsghandlers.NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManager, RicServiceUpdateManager)}, {rmrCgo.RIC_E2NODE_CONFIG_UPDATE, rmrmsghandlers.NewE2nodeConfigUpdateNotificationHandler(logger, rnibDataService, rmrSender)}, {rmrCgo.RIC_E2_RESET_REQ, rmrmsghandlers.NewE2ResetRequestNotificationHandler(logger, rnibDataService, config, rmrSender, ranResetManager, changeStatusToConnectedRanManager)}, } @@ -106,7 +107,7 @@ func TestGetNotificationHandlerSuccess(t *testing.T) { for _, tc := range testCases { provider := NewNotificationHandlerProvider() - provider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) + provider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager) t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) { handler, err := provider.GetNotificationHandler(tc.msgType) if err != nil { @@ -135,9 +136,9 @@ func TestGetNotificationHandlerFailure(t *testing.T) { } for _, tc := range testCases { - logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager := initTestCase(t) + logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager := initTestCase(t) provider := NewNotificationHandlerProvider() - provider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) + provider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager) t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) { _, err := provider.GetNotificationHandler(tc.msgType) if err == nil { diff --git a/E2Manager/rmrCgo/rmrCgoApi.go b/E2Manager/rmrCgo/rmrCgoApi.go index 5ec09b9..fc5c849 100644 --- a/E2Manager/rmrCgo/rmrCgoApi.go +++ b/E2Manager/rmrCgo/rmrCgoApi.go @@ -76,6 +76,10 @@ func (ctx *Context) SendMsg(msg *MBuf, printLogs bool) (*MBuf, error) { currCMBuf := C.rmr_send_msg(ctx.RmrCtx, allocatedCMBuf) defer C.rmr_free_msg(currCMBuf) + if currCMBuf == nil { + errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - currCMBuf is empty hence return from message") + return nil, errors.New(errorMessage) + } state = currCMBuf.state diff --git a/E2Manager/rmrCgo/rmrCgoTypes.go b/E2Manager/rmrCgo/rmrCgoTypes.go index 2b5c31b..47c2b1f 100644 --- a/E2Manager/rmrCgo/rmrCgoTypes.go +++ b/E2Manager/rmrCgo/rmrCgoTypes.go @@ -89,6 +89,7 @@ const ( RIC_E2NODE_CONFIG_UPDATE_FAILURE = C.RIC_E2NODE_CONFIG_UPDATE_FAILURE RIC_E2_RESET_REQ = C.RIC_E2_RESET_REQ RIC_E2_RESET_RESP = C.RIC_E2_RESET_RESP + RIC_E2_RIC_ERROR_INDICATION = C.RIC_E2_RIC_ERROR_INDICATION ) const ( diff --git a/E2Manager/rmrCgo/rmrCgoUtils.go b/E2Manager/rmrCgo/rmrCgoUtils.go index 64ff50f..c9d1147 100644 --- a/E2Manager/rmrCgo/rmrCgoUtils.go +++ b/E2Manager/rmrCgo/rmrCgoUtils.go @@ -63,6 +63,9 @@ func (ctx *Context) getAllocatedCRmrMBuf(logger *logger.Logger, mBuf *MBuf, maxM var meidBuf[RMR_MAX_MEID_LEN]byte cMBuf = C.rmr_alloc_msg(ctx.RmrCtx, C.int(maxMsgSize)) + if cMBuf == nil { + return nil + } cMBuf.mtype = C.int(mBuf.MType) cMBuf.len = C.int(mBuf.Len) diff --git a/E2Manager/services/rmrreceiver/rmr_receiver_test.go b/E2Manager/services/rmrreceiver/rmr_receiver_test.go index 2b1b38d..21abcfe 100644 --- a/E2Manager/services/rmrreceiver/rmr_receiver_test.go +++ b/E2Manager/services/rmrreceiver/rmr_receiver_test.go @@ -73,10 +73,11 @@ func initRmrReceiver(logger *logger.Logger) *RmrReceiver { routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) ranListManager := managers.NewRanListManager(logger, rnibDataService) ranAlarmService := services.NewRanAlarmService(logger, config) + RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService) ranConnectStatusChangeManager := managers.NewRanConnectStatusChangeManager(logger, rnibDataService, ranListManager, ranAlarmService) e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManager, routingManagerClient, ranConnectStatusChangeManager) rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() - rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager) + rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, e2tInstancesManager, routingManagerClient, e2tAssociationManager, ranConnectStatusChangeManager, ranListManager, RicServiceUpdateManager) notificationManager := notificationmanager.NewNotificationManager(logger, rmrNotificationHandlerProvider) return NewRmrReceiver(logger, rmrMessenger, notificationManager) } diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationForDefault.xml b/E2Manager/tests/resources/errorIndication/errorIndicationForDefault.xml new file mode 100644 index 0000000..e2310f6 --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationForDefault.xml @@ -0,0 +1,56 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + 1 + + + + + + + + + 2 + + + + 8 + + + + + + + + + + \ No newline at end of file diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationForServiceUpdate.xml b/E2Manager/tests/resources/errorIndication/errorIndicationForServiceUpdate.xml new file mode 100644 index 0000000..64fedf9 --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationForServiceUpdate.xml @@ -0,0 +1,56 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + 1 + + + + + + + + + 2 + + + + 7 + + + + + + + + + + \ No newline at end of file diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationForSetupRequest.xml b/E2Manager/tests/resources/errorIndication/errorIndicationForSetupRequest.xml new file mode 100644 index 0000000..d35237b --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationForSetupRequest.xml @@ -0,0 +1,56 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + 1 + + + + + + + + + 2 + + + + 1 + + + + + + + + + + \ No newline at end of file diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationInvalid.xml b/E2Manager/tests/resources/errorIndication/errorIndicationInvalid.xml new file mode 100644 index 0000000..f88722c --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationInvalid.xml @@ -0,0 +1,55 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + 1 + + + + + + + + + 2 + + + + 7 + + + + + + + + + \ No newline at end of file diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationUnsuccessfulOutcome.xml b/E2Manager/tests/resources/errorIndication/errorIndicationUnsuccessfulOutcome.xml new file mode 100644 index 0000000..c45e110 --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationUnsuccessfulOutcome.xml @@ -0,0 +1,56 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + 1 + + + + + + + + + 2 + + + + 7 + + + + + + + + + + \ No newline at end of file diff --git a/E2Manager/tests/resources/errorIndication/errorIndicationWithoutCD.xml b/E2Manager/tests/resources/errorIndication/errorIndicationWithoutCD.xml new file mode 100644 index 0000000..21e422d --- /dev/null +++ b/E2Manager/tests/resources/errorIndication/errorIndicationWithoutCD.xml @@ -0,0 +1,36 @@ + + + 2 + + + + + + 49 + + + 22 + + + + 29 + + + + 1 + 1 + + + + + 5 + + + 4 + + + + + + + \ No newline at end of file -- 2.16.6