2 // Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 // This source code is part of the near-RT RIC (RAN Intelligent Controller)
17 // platform project (RICP).
19 package rmrmsghandlers
32 "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
33 "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
34 "github.com/stretchr/testify/assert"
35 "github.com/stretchr/testify/mock"
40 serviceUpdateE2tInstanceAddress = "10.0.0.27:9999"
41 serviceUpdateE2SetupMsgPrefix = serviceUpdateE2tInstanceAddress + "|"
42 serviceUpdateRANName = "gnb:TestRan"
43 RanManipulationMessageChannel = "RAN_MANIPULATION"
44 RICServiceUpdate_E2SetupReqPath = "../../tests/resources/serviceUpdate/RicServiceUpdate_SetupRequest.xml"
45 RicServiceUpdateModifiedPath = "../../tests/resources/serviceUpdate/RicServiceUpdate_ModifiedFunction.xml"
46 RicServiceUpdateDeletePath = "../../tests/resources/serviceUpdate/RicServiceUpdate_DeleteFunction.xml"
47 RicServiceUpdateAddedPath = "../../tests/resources/serviceUpdate/RicServiceUpdate_AddedFunction.xml"
48 RicServiceUpdateEmptyPath = "../../tests/resources/serviceUpdate/RicServiceUpdate_Empty.xml"
49 RicServiceUpdateAckModifiedPath = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_ModifiedFunction.xml"
50 RicServiceUpdateAckAddedPath = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_AddedFunction.xml"
51 RicServiceUpdateAckDeletePath = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_DeleteFunction.xml"
52 RicServiceUpdateAckEmptyPath = "../../tests/resources/serviceUpdateAck/RicServiceUpdateAck_Empty.xml"
55 func initRicServiceUpdateHandler(t *testing.T) (*RicServiceUpdateHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.RanListManagerMock) {
56 logger := tests.InitLog(t)
57 config := &configuration.Configuration{
58 RnibRetryIntervalMs: 10,
59 MaxRnibConnectionAttempts: 3,
60 RnibWriter: configuration.RnibWriterConfig{
61 StateChangeMessageChannel: StateChangeMessageChannel,
62 RanManipulationMessageChannel: RanManipulationMessageChannel,
73 rmrMessengerMock := &mocks.RmrMessengerMock{}
74 rmrSender := tests.InitRmrSender(rmrMessengerMock, logger)
75 readerMock := &mocks.RnibReaderMock{}
76 writerMock := &mocks.RnibWriterMock{}
77 rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
78 ranListManagerMock := &mocks.RanListManagerMock{}
79 handler := NewRicServiceUpdateHandler(logger, rmrSender, rnibDataService, ranListManagerMock)
80 return handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock
84 func TestRICServiceUpdateModifiedFuncSuccess(t *testing.T){
85 testServiceUpdateSuccess(t, RicServiceUpdateModifiedPath, RicServiceUpdateAckModifiedPath)
88 func TestRICServiceUpdateAddedFuncSuccess(t *testing.T){
90 testServiceUpdateSuccess(t, RicServiceUpdateAddedPath, RicServiceUpdateAckAddedPath)
93 func TestRICServiceUpdateDeleteFuncSuccess(t *testing.T){
94 testServiceUpdateSuccess(t, RicServiceUpdateDeletePath, RicServiceUpdateAckDeletePath)
97 func TestRICServiceUpdateEmptySuccess(t *testing.T){
98 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
99 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateEmptyPath)
100 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
101 nb1:= createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
102 oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
103 newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
104 readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
105 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
106 ricServiceAckMsg := createRicServiceQueryAckRMRMbuf(t,RicServiceUpdateAckEmptyPath, notificationRequest )
107 ranListManagerMock.On("UpdateHealthcheckTimeStampReceived",nb1.RanName).Return(oldnbIdentity, newnbIdentity)
108 ranListManagerMock.On("UpdateNbIdentities",nb1.NodeType, []*entities.NbIdentity{oldnbIdentity}, []*entities.NbIdentity{newnbIdentity}).Return(nil)
109 rmrMessengerMock.On("SendMsg",ricServiceAckMsg,true).Return(&rmrCgo.MBuf{}, nil)
111 handler.Handle(notificationRequest)
112 writerMock.AssertExpectations(t)
113 rmrMessengerMock.AssertNumberOfCalls(t,"SendMsg", 1)
114 readerMock.AssertExpectations(t)
115 ranListManagerMock.AssertExpectations(t)
118 func TestRICServiceUpdateRnibFailure(t *testing.T){
119 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
120 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
121 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
122 readerMock.On("GetNodeb", serviceUpdateRANName).Return(&entities.NodebInfo{}, common.NewInternalError(fmt.Errorf("internal error")))
123 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
125 handler.Handle(notificationRequest)
126 writerMock.AssertExpectations(t)
127 rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
128 readerMock.AssertExpectations(t)
129 ranListManagerMock.AssertExpectations(t)
132 func TestRICServiceUpdateRnibNotFound(t *testing.T){
133 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
134 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateModifiedPath)
135 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
136 readerMock.On("GetNodeb", serviceUpdateRANName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("nodeb not found"))
137 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
139 handler.Handle(notificationRequest)
140 writerMock.AssertExpectations(t)
141 rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
142 readerMock.AssertExpectations(t)
143 ranListManagerMock.AssertExpectations(t)
146 func TestRICServiceUpdateNodeBInfoFailure(t *testing.T){
147 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
148 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
149 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
150 nb1:= createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
151 readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
152 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
153 writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(common.NewInternalError(fmt.Errorf("internal error")))
155 handler.Handle(notificationRequest)
156 writerMock.AssertExpectations(t)
157 rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything)
158 readerMock.AssertExpectations(t)
159 ranListManagerMock.AssertExpectations(t)
162 func TestSendRICServiceUpdateAckFailure(t *testing.T){
163 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
164 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateModifiedPath)
165 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
166 nb1:= createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
167 oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
168 newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
169 readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
170 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
171 ricServiceAckMsg := createRicServiceQueryAckRMRMbuf(t,RicServiceUpdateAckModifiedPath, notificationRequest )
172 ranListManagerMock.On("UpdateHealthcheckTimeStampReceived",nb1.RanName).Return(oldnbIdentity, newnbIdentity)
173 writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
174 rmrMessengerMock.On("SendMsg",ricServiceAckMsg,true).Return(&rmrCgo.MBuf{}, fmt.Errorf("rmr send failure"))
175 ranListManagerMock.On("UpdateNbIdentities",nb1.NodeType, []*entities.NbIdentity{oldnbIdentity}, []*entities.NbIdentity{newnbIdentity}).Return(nil)
177 handler.Handle(notificationRequest)
178 writerMock.AssertExpectations(t)
179 rmrMessengerMock.AssertNumberOfCalls(t,"SendMsg", 1)
180 readerMock.AssertExpectations(t)
181 ranListManagerMock.AssertExpectations(t)
184 func TestRICServiceUpdateUpdateNbIdentitiesFailure(t *testing.T){
185 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
186 xmlserviceUpdate := utils.ReadXmlFile(t, RicServiceUpdateDeletePath)
187 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
188 nb1:= createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
189 oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
190 newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
191 readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
192 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName, Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
193 ranListManagerMock.On("UpdateHealthcheckTimeStampReceived",nb1.RanName).Return(oldnbIdentity, newnbIdentity)
194 ranListManagerMock.On("UpdateNbIdentities",nb1.NodeType, []*entities.NbIdentity{oldnbIdentity}, []*entities.NbIdentity{newnbIdentity}).Return(common.NewInternalError(fmt.Errorf("internal error")))
195 writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
197 handler.Handle(notificationRequest)
198 writerMock.AssertExpectations(t)
199 rmrMessengerMock.AssertNumberOfCalls(t,"SendMsg", 0)
200 readerMock.AssertExpectations(t)
201 ranListManagerMock.AssertExpectations(t)
204 func TestRICServiceUpdateParseRequest_PipFailure(t *testing.T) {
205 xmlGnb := utils.ReadXmlFile(t, RICServiceUpdate_E2SetupReqPath)
206 handler, _, _, _, _:= initRicServiceUpdateHandler(t)
207 prefBytes := []byte(serviceUpdateE2tInstanceAddress)
208 ricServiceUpdate, err := handler.parseSetupRequest(append(prefBytes, xmlGnb...))
209 assert.Nil(t, ricServiceUpdate)
210 assert.NotNil(t, err)
211 assert.EqualError(t, err, "#RicServiceUpdateHandler.parseSetupRequest - Error parsing RIC SERVICE UPDATE failed extract Payload: no | separator found")
214 func TestRICServiceUppdateParseRequest_UnmarshalFailure(t *testing.T) {
215 handler, _, _, _, _ := initRicServiceUpdateHandler(t)
216 prefBytes := []byte(serviceUpdateE2SetupMsgPrefix)
217 ricServiceUpdate, err := handler.parseSetupRequest(append(prefBytes, 1, 2, 3))
218 assert.Nil(t, ricServiceUpdate)
219 assert.NotNil(t, err)
220 assert.EqualError(t, err, "#RicServiceUpdateHandler.parseSetupRequest - Error unmarshalling RIC SERVICE UPDATE payload: 31302e302e302e32373a393939397c010203")
223 func testServiceUpdateSuccess(t *testing.T, servicepdatePath string, serviceUpdateAckPath string){
224 handler, readerMock, writerMock, rmrMessengerMock, ranListManagerMock := initRicServiceUpdateHandler(t)
225 xmlserviceUpdate := utils.ReadXmlFile(t, servicepdatePath)
226 xmlserviceUpdate = utils.CleanXML(xmlserviceUpdate)
227 nb1:= createNbInfo(t, serviceUpdateRANName, entities.ConnectionStatus_CONNECTED)
228 oldnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
229 newnbIdentity := &entities.NbIdentity{InventoryName: nb1.RanName, ConnectionStatus: nb1.ConnectionStatus}
230 readerMock.On("GetNodeb", nb1.RanName).Return(nb1, nil)
231 notificationRequest := &models.NotificationRequest{RanName: serviceUpdateRANName,
232 Payload: append([]byte(serviceUpdateE2SetupMsgPrefix), xmlserviceUpdate...)}
233 ricServiceAckMsg := createRicServiceQueryAckRMRMbuf(t,serviceUpdateAckPath, notificationRequest )
234 ranListManagerMock.On("UpdateHealthcheckTimeStampReceived",nb1.RanName).Return(oldnbIdentity, newnbIdentity)
235 ranListManagerMock.On("UpdateNbIdentities",nb1.NodeType, []*entities.NbIdentity{oldnbIdentity},
236 []*entities.NbIdentity{newnbIdentity}).Return(nil)
237 writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
238 rmrMessengerMock.On("SendMsg",ricServiceAckMsg,true).Return(&rmrCgo.MBuf{}, nil)
240 handler.Handle(notificationRequest)
241 writerMock.AssertExpectations(t)
242 rmrMessengerMock.AssertNumberOfCalls(t,"SendMsg", 1)
243 readerMock.AssertExpectations(t)
244 ranListManagerMock.AssertExpectations(t)
247 func createRicServiceQueryAckRMRMbuf(t *testing.T, xmlFile string, req *models.NotificationRequest) *rmrCgo.MBuf{
248 ricServiceQueryAckXml := utils.ReadXmlFile(t, xmlFile)
249 ricServiceQueryAckXml = utils.CleanXML(ricServiceQueryAckXml)
250 payLoad := utils.NormalizeXml(ricServiceQueryAckXml)
252 xAction := req.TransactionId
253 msgsrc := req.GetMsgSrc()
255 rmrMessage := models.NewRmrMessage(rmrCgo.RIC_SERVICE_UPDATE_ACK, serviceUpdateRANName, payLoad, xAction, msgsrc)
256 return rmrCgo.NewMBuf(rmrMessage.MsgType, len(rmrMessage.Payload), rmrMessage.RanName, &rmrMessage.Payload, &rmrMessage.XAction, rmrMessage.GetMsgSrc())
259 func createNbInfo(t *testing.T, RanName string, connectionStatus entities.ConnectionStatus) *entities.NodebInfo {
260 xmlgnb := utils.ReadXmlFile(t, RICServiceUpdate_E2SetupReqPath)
261 xmlgnb = utils.CleanXML(xmlgnb)
262 payload := append([]byte(serviceUpdateE2SetupMsgPrefix), xmlgnb...)
263 pipInd := bytes.IndexByte(payload, '|')
264 setupRequest := &models.E2SetupRequestMessage{}
265 err := xml.Unmarshal(utils.NormalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU)
270 nodeb := &entities.NodebInfo{
271 AssociatedE2TInstanceAddress: serviceUpdateE2tInstanceAddress,
273 SetupFromNetwork: true,
274 NodeType: entities.Node_GNB,
275 ConnectionStatus: connectionStatus,
276 Configuration: &entities.NodebInfo_Gnb{
278 GnbType: entities.GnbType_GNB,
279 RanFunctions: setupRequest.ExtractRanFunctionsList(),
282 GlobalNbId: &entities.GlobalNbId{
283 PlmnId: setupRequest.GetPlmnId(),
284 NbId: setupRequest.GetNbId(),