RIC-997: ErrorIndication handling in e2mgr
[ric-plt/e2mgr.git] / E2Manager / handlers / rmrmsghandlers / ric_service_update_handler_test.go
1 //
2 // Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
17 //  platform project (RICP).
18
19 package rmrmsghandlers
20
21 import (
22         "bytes"
23         "e2mgr/configuration"
24         "e2mgr/mocks"
25         "e2mgr/models"
26         "e2mgr/rmrCgo"
27         "e2mgr/services"
28         "e2mgr/tests"
29         "e2mgr/utils"
30         "encoding/xml"
31         "fmt"
32         "testing"
33
34         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
35         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
36         "github.com/stretchr/testify/assert"
37         "github.com/stretchr/testify/mock"
38         "e2mgr/managers"
39 )
40
41 const (
42         serviceUpdateE2tInstanceAddress = "10.0.0.27:9999"
43         serviceUpdateE2SetupMsgPrefix   = serviceUpdateE2tInstanceAddress + "|"
44         serviceUpdateRANName            = "gnb:TestRan"
45         RanManipulationMessageChannel   = "RAN_MANIPULATION"
46         RICServiceUpdate_E2SetupReqPath = "../../tests/resources/serviceUpdate/RicServiceUpdate_SetupRequest.xml"
47         RicServiceUpdateModifiedPath    = "../../tests/resources/serviceUpdate/RicServiceUpdate_ModifiedFunction.xml"
48         RicServiceUpdateDeletePath      = "../../tests/resources/serviceUpdate/RicServiceUpdate_DeleteFunction.xml"
49         RicServiceUpdateAddedPath       = "../../tests/resources/serviceUpdate/RicServiceUpdate_AddedFunction.xml"
50         RicServiceUpdateEmptyPath       = "../../tests/resources/serviceUpdate/RicServiceUpdate_Empty.xml"
51         RicServiceUpdateAckModifiedPath = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_ModifiedFunction.xml"
52         RicServiceUpdateAckAddedPath    = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_AddedFunction.xml"
53         RicServiceUpdateAckDeletePath   = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_DeleteFunction.xml"
54         RicServiceUpdateAckEmptyPath    = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_Empty.xml"
55 )
56
57 func initRicServiceUpdateHandler(t *testing.T) (*RicServiceUpdateHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.RanListManagerMock) {
58         logger := tests.InitLog(t)
59         config := &configuration.Configuration{
60                 RnibRetryIntervalMs:       10,
61                 MaxRnibConnectionAttempts: 3,
62                 RnibWriter: configuration.RnibWriterConfig{
63                         StateChangeMessageChannel:     StateChangeMessageChannel,
64                         RanManipulationMessageChannel: RanManipulationMessageChannel,
65                 },
66                 GlobalRicId: struct {
67                         RicId string
68                         Mcc   string
69                         Mnc   string
70                 }{
71                         Mcc:   "337",
72                         Mnc:   "94",
73                         RicId: "AACCE",
74                 }}
75         rmrMessengerMock := &mocks.RmrMessengerMock{}
76         rmrSender := tests.InitRmrSender(rmrMessengerMock, logger)
77         readerMock := &mocks.RnibReaderMock{}
78         writerMock := &mocks.RnibWriterMock{}
79         rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
80         ranListManagerMock := &mocks.RanListManagerMock{}
81         RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService)
82         handler := NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManagerMock, RicServiceUpdateManager)
83         return handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock
84 }
85
86 func TestRICServiceUpdateModifiedFuncSuccess(t *testing.T) {
87         testServiceUpdateSuccess(t, RicServiceUpdateModifiedPath, RicServiceUpdateAckModifiedPath)
88 }
89
90 func TestRICServiceUpdateAddedFuncSuccess(t *testing.T) {
91
92         testServiceUpdateSuccess(t, RicServiceUpdateAddedPath, RicServiceUpdateAckAddedPath)
93 }
94
95 func TestRICServiceUpdateDeleteFuncSuccess(t *testing.T) {
96         testServiceUpdateSuccess(t, RicServiceUpdateDeletePath, RicServiceUpdateAckDeletePath)
97 }
98
99 func TestRICServiceUpdateRnibFailure(t *testing.T) {
100         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
101         xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
102         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
103         readerMock.On("GetNodeb", serviceUpdateRANName).Return(&entities.NodebInfo{}, common.NewInternalError(fmt.Errorf("internal error")))
104         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
105
106         handler.Handle(notificationRequest)
107         writerMock.AssertExpectations(t)
108         rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
109         readerMock.AssertExpectations(t)
110         ranListManagerMock.AssertExpectations(t)
111 }
112
113 func TestRICServiceUpdateRnibNotFound(t *testing.T) {
114         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
115         xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateModifiedPath)
116         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
117         readerMock.On("GetNodeb", serviceUpdateRANName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("nodeb not found"))
118         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
119
120         handler.Handle(notificationRequest)
121         writerMock.AssertExpectations(t)
122         rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
123         readerMock.AssertExpectations(t)
124         ranListManagerMock.AssertExpectations(t)
125 }
126
127 func TestRICServiceUpdateNodeBInfoFailure(t *testing.T) {
128         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
129         xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
130         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
131         nb1 := createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
132         readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
133         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
134         writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(common.NewInternalError(fmt.Errorf("internal error")))
135
136         handler.Handle(notificationRequest)
137         writerMock.AssertExpectations(t)
138         rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
139         readerMock.AssertExpectations(t)
140         ranListManagerMock.AssertExpectations(t)
141 }
142
143 func TestSendRICServiceUpdateAckFailure(t *testing.T) {
144         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
145         xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateModifiedPath)
146         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
147         nb1 := createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
148         oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
149         newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
150         readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
151         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
152         ricServiceAckMsg := createRicServiceQueryAckRMRMbuf(t, RicServiceUpdateAckModifiedPath, notificationRequest)
153         ranListManagerMock.On("UpdateHealthcheckTimeStampReceived", nb1.RanName).Return(oldnbIdentity, newnbIdentity)
154         writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
155         rmrMessengerMock.On("SendMsg", ricServiceAckMsg, true).Return(&rmrCgo.MBuf{}, fmt.Errorf("rmr send failure"))
156         ranListManagerMock.On("UpdateNbIdentities", nb1.NodeType, []*entities.NbIdentity{oldnbIdentity}, []*entities.NbIdentity{newnbIdentity}).Return(nil)
157
158         handler.Handle(notificationRequest)
159         writerMock.AssertExpectations(t)
160         rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
161         readerMock.AssertExpectations(t)
162         ranListManagerMock.AssertExpectations(t)
163 }
164
165 func TestRICServiceUpdateUpdateNbIdentitiesFailure(t *testing.T) {
166         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
167         xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
168         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
169         nb1 := createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
170         oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
171         newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
172         readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
173         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
174         ranListManagerMock.On("UpdateHealthcheckTimeStampReceived", nb1.RanName).Return(oldnbIdentity, newnbIdentity)
175         ranListManagerMock.On("UpdateNbIdentities", nb1.NodeType, []*entities.NbIdentity{oldnbIdentity}, []*entities.NbIdentity{newnbIdentity}).Return(common.NewInternalError(fmt.Errorf("internal error")))
176         writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
177
178         handler.Handle(notificationRequest)
179         writerMock.AssertExpectations(t)
180         rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0)
181         readerMock.AssertExpectations(t)
182         ranListManagerMock.AssertExpectations(t)
183 }
184
185 func TestRICServiceUpdateParseRequest_PipFailure(t *testing.T) {
186         xmlGnb := utils.ReadXmlFile(t, RICServiceUpdate_E2SetupReqPath)
187         handler, _, _, _, _ := initRicServiceUpdateHandler(t)
188         prefBytes := []byte(serviceUpdateE2tInstanceAddress)
189         ricServiceUpdate, err := handler.parseSetupRequest(append(prefBytes, xmlGnb...))
190         assert.Nil(t, ricServiceUpdate)
191         assert.NotNil(t, err)
192         assert.EqualError(t, err, "#RicServiceUpdateHandler.parseSetupRequest - Error parsing RIC SERVICE UPDATE failed extract Payload: no | separator found")
193 }
194
195 func TestRICServiceUppdateParseRequest_UnmarshalFailure(t *testing.T) {
196         handler, _, _, _, _ := initRicServiceUpdateHandler(t)
197         prefBytes := []byte(serviceUpdateE2SetupMsgPrefix)
198         ricServiceUpdate, err := handler.parseSetupRequest(append(prefBytes, 1, 2, 3))
199         assert.Nil(t, ricServiceUpdate)
200         assert.NotNil(t, err)
201         assert.EqualError(t, err, "#RicServiceUpdateHandler.parseSetupRequest - Error unmarshalling RIC SERVICE UPDATE payload: 31302e302e302e32373a393939397c010203")
202 }
203
204 func testServiceUpdateSuccess(t *testing.T, servicepdatePath string, serviceUpdateAckPath string) {
205         handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
206         xmlserviceUpdate := utils.ReadXmlFile(t, servicepdatePath)
207         xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
208         nb1 := createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
209         oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
210         newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
211         readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
212         notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName,
213                 Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
214         ricServiceAckMsg := createRicServiceQueryAckRMRMbuf(t, serviceUpdateAckPath, notificationRequest)
215         ranListManagerMock.On("UpdateHealthcheckTimeStampReceived", nb1.RanName).Return(oldnbIdentity, newnbIdentity)
216         ranListManagerMock.On("UpdateNbIdentities", nb1.NodeType, []*entities.NbIdentity{oldnbIdentity},
217                 []*entities.NbIdentity{newnbIdentity}).Return(nil)
218         writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
219         rmrMessengerMock.On("SendMsg", ricServiceAckMsg, true).Return(&rmrCgo.MBuf{}, nil)
220
221         handler.Handle(notificationRequest)
222         writerMock.AssertExpectations(t)
223         rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
224         readerMock.AssertExpectations(t)
225         ranListManagerMock.AssertExpectations(t)
226 }
227
228 func createRicServiceQueryAckRMRMbuf(t *testing.T, xmlFile string, req *models.NotificationRequest) *rmrCgo.MBuf {
229         ricServiceQueryAckXml := utils.ReadXmlFile(t, xmlFile)
230         ricServiceQueryAckXml = utils.CleanXML(ricServiceQueryAckXml)
231         payLoad := utils.NormalizeXml(ricServiceQueryAckXml)
232
233         xAction := req.TransactionId
234         msgsrc := req.GetMsgSrc()
235
236         rmrMessage := models.NewRmrMessage(rmrCgo.RIC_SERVICE_UPDATE_ACK, serviceUpdateRANName, payLoad, xAction, msgsrc)
237         return rmrCgo.NewMBuf(rmrMessage.MsgType, len(rmrMessage.Payload), rmrMessage.RanName, &rmrMessage.Payload, &rmrMessage.XAction, rmrMessage.GetMsgSrc())
238 }
239
240 func createNbInfo(t *testing.T, RanName string, connectionStatus entities.ConnectionStatus) *entities.NodebInfo {
241         xmlgnb := utils.ReadXmlFile(t, RICServiceUpdate_E2SetupReqPath)
242         xmlgnb = utils.CleanXML(xmlgnb)
243         payload := append([]byte(serviceUpdateE2SetupMsgPrefix), xmlgnb...)
244         pipInd := bytes.IndexByte(payload, '|')
245         setupRequest := &models.E2SetupRequestMessage{}
246         err := xml.Unmarshal(utils.NormalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU)
247         if err != nil {
248                 t.Fatal(err)
249         }
250
251         nodeb := &entities.NodebInfo{
252                 AssociatedE2TInstanceAddress: serviceUpdateE2tInstanceAddress,
253                 RanName:                      RanName,
254                 SetupFromNetwork:             true,
255                 NodeType:                     entities.Node_GNB,
256                 ConnectionStatus:             connectionStatus,
257                 Configuration: &entities.NodebInfo_Gnb{
258                         Gnb: &entities.Gnb{
259                                 GnbType:      entities.GnbType_GNB,
260                                 RanFunctions: setupRequest.ExtractRanFunctionsList(),
261                         },
262                 },
263                 GlobalNbId: &entities.GlobalNbId{
264                         PlmnId: setupRequest.GetPlmnId(),
265                         NbId:   setupRequest.GetNbId(),
266                 },
267         }
268         return nodeb
269 }