RIC-997: ErrorIndication handling in e2mgr
[ric-plt/e2mgr.git] / E2Manager / handlers / rmrmsghandlers / error_indication_notification_handler_test.go
1 // Copyright 2023 Nokia
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
16 //  platform project (RICP)
17
18 package rmrmsghandlers
19
20 import (
21         "bytes"
22         "e2mgr/clients"
23         "e2mgr/configuration"
24         "e2mgr/managers"
25         "e2mgr/mocks"
26         "e2mgr/models"
27         "e2mgr/tests"
28         "e2mgr/services"
29         "e2mgr/utils"
30         "encoding/json"
31         "io/ioutil"
32         "net/http"
33         "testing"
34         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
35         "github.com/stretchr/testify/assert"
36         "github.com/stretchr/testify/mock"
37 )
38
39 const (
40         RanNameForErrorIndication        = "test"
41         E2tAddress                       = "10.10.2.15:9800"
42         e2tInstanceFullAddressErrorIndication          = "10.0.2.15:9999"
43         e2SetupMsgPrefixErrorIndication                = e2tInstanceFullAddressErrorIndication + "|"
44         ErrorIndicationXmlPath           = "../../tests/resources/errorIndication/ErrorIndicationForSetupRequest.xml"
45         ErrorIndicationWithoutCDXmlPath           = "../../tests/resources/errorIndication/ErrorIndicationWithoutCD.xml"
46         ErrorIndicationXmlPathServiceUpdate = "../../tests/resources/errorIndication/ErrorIndicationForServiceUpdate.xml"
47         ErrorIndicationXmlPathUnsuccessfuOutcome =  "../../tests/resources/errorIndication/ErrorIndicationUnsuccessfulOutcome.xml"
48         ErrorIndicationXmlPathDefault = "../../tests/resources/errorIndication/ErrorIndicationForDefault.xml"
49         ErrorIndicationInvalidXmlPath = "../../tests/resources/errorIndication/ErrorIndicationInvalid.xml"
50 )
51
52 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) {
53         logger := tests.InitLog(t)
54         config := &configuration.Configuration{
55                 RnibRetryIntervalMs:       10,
56                 MaxRnibConnectionAttempts: 3,
57                 RnibWriter: configuration.RnibWriterConfig{
58                         StateChangeMessageChannel: StateChangeMessageChannel,
59                 },
60                 GlobalRicId: struct {
61                         RicId string
62                         Mcc   string
63                         Mnc   string
64                 }{Mcc: "327", Mnc: "94", RicId: "AACCE"}}
65         rmrMessengerMock := &mocks.RmrMessengerMock{}
66         readerMock := &mocks.RnibReaderMock{}
67         writerMock := &mocks.RnibWriterMock{}
68         RanDisconnectionManagerMock := &mocks.RanDisconnectionManagerMock{}
69         ricServiceUpdateManagerMock := &mocks.RicServiceUpdateManagerMock{}
70         MockLogger := &mocks.MockLogger{}
71         routingManagerClientMock := &mocks.RoutingManagerClientMock{}
72         rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
73         e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{}
74         httpClientMock := &mocks.HttpClientMock{}
75         ranListManagerMock := &mocks.RanListManagerMock{}
76
77         ranListManager := managers.NewRanListManager(logger, rnibDataService)
78         ranAlarmService := services.NewRanAlarmService(logger, config)
79         ranConnectStatusChangeManager := managers.NewRanConnectStatusChangeManager(logger, rnibDataService, ranListManager, ranAlarmService)
80         e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManagerMock, routingManagerClientMock, ranConnectStatusChangeManager)
81         ranDisconnectionManager := managers.NewRanDisconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, e2tAssociationManager, ranConnectStatusChangeManager)
82         RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService)
83         handler := ErrorIndicationNotificationHandler(logger, ranDisconnectionManager, RicServiceUpdateManager)
84
85         return handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock, ranListManager, RanDisconnectionManagerMock, ricServiceUpdateManagerMock,MockLogger,httpClientMock,ranListManagerMock
86 }
87
88 func TestParseErrorIndicationMessage_Success(t *testing.T) {
89         ErrorgnbXml := utils.ReadXmlFile(t, ErrorIndicationXmlPath)
90         handler, _, _, _, _, _, _, _, _,_,_,_ := initErrorIndication(t)
91         prefBytes := []byte(e2SetupMsgPrefixErrorIndication)
92         errorIndicationMessage, err := handler.parseErrorIndication(append(prefBytes, ErrorgnbXml...))
93         assert.NotNil(t, errorIndicationMessage)
94         assert.Nil(t, err)
95 }
96
97 func TestParseErrorIndication_PipFailure(t *testing.T) {
98         ErrorgnbXml := utils.ReadXmlFile(t, ErrorIndicationXmlPath)
99         handler, _, _, _, _, _,_ ,_, _, _,_,_ := initErrorIndication(t)
100         prefBytes := []byte("10.0.2.15:9999")
101         request, err := handler.parseErrorIndication(append(prefBytes, ErrorgnbXml...))
102         assert.Nil(t, request)
103         assert.NotNil(t, err)
104         assert.EqualError(t, err, "#ErrorIndicationHandler.parseErrorIndication - Error parsing ERROR INDICATION failed extract Payload: no | separator found")
105 }
106 func TestParseErrorIndicationMessage_UnmarshalFailure(t *testing.T) {
107         handler, _,_, _, _, _, _, _, _, _,_,_ := initErrorIndication(t)
108         prefBytes := []byte(e2SetupMsgPrefixErrorIndication)
109         errorIndicationMessage, err := handler.parseErrorIndication(append(prefBytes, 1, 2, 3))
110         assert.Nil(t, errorIndicationMessage)
111         assert.NotNil(t, err)
112         assert.EqualError(t, err, "#ErrorIndicationHandler.parseErrorIndication - Error unmarshalling ERROR INDICATION payload: 31302e302e322e31353a393939397c010203")
113 }
114
115 func testErrorIndicationNotificationHandler(t *testing.T) {
116         handler, readerMock, writerMock, _, _, _, _, _, _,_ ,_,_:= initErrorIndication(t)
117         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
118         notificationRequest := models.NotificationRequest{RanName: RanNameForErrorIndication}
119         handler.Handle(&notificationRequest)
120         readerMock.AssertExpectations(t)
121         writerMock.AssertExpectations(t)
122 }
123
124 func testErrorIndicationHandlerWhenConnectedRanSuccess(t *testing.T,xmlPath string) {
125         xml := utils.ReadXmlFile(t, xmlPath)
126         handler, readerMock, writerMock, _, e2tInstancesManagerMock,routingManagerClientMock, _, _, _, _,httpClientMock,_ := initErrorIndication(t)
127         origNodebInfo := &entities.NodebInfo{
128                 RanName:                      RanNameForErrorIndication,
129                 GlobalNbId:                   &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"},
130                 ConnectionStatus:             entities.ConnectionStatus_CONNECTED,
131                 AssociatedE2TInstanceAddress: E2tAddress,
132         }
133
134         models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureCompleted)
135         var rnibErr error
136         readerMock.On("GetNodeb", RanNameForErrorIndication).Return(origNodebInfo, rnibErr)
137         updatedNodebInfo1 := *origNodebInfo
138         updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
139         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanNameForErrorIndication+"_DISCONNECTED").Return(rnibErr)
140         updatedNodebInfo2 := *origNodebInfo
141         updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
142         updatedNodebInfo2.AssociatedE2TInstanceAddress = ""
143         writerMock.On("UpdateNodebInfo", mock.Anything).Return(rnibErr)
144         e2tInstance := &entities.E2TInstance{Address: E2tAddress, AssociatedRanList: []string{RanNameForErrorIndication}}
145         readerMock.On("GetE2TInstance", E2tAddress).Return(e2tInstance, nil).Maybe()
146         e2tInstanceToSave := *e2tInstance
147         e2tInstanceToSave.AssociatedRanList = []string{}
148         //writerMock.On("SaveE2TInstance", &e2tInstanceToSave).Return(nil)
149         mockHttpClientForErrorIndication(httpClientMock, true) //After uncommenting testcase is failing 
150         e2tInstancesManagerMock.On("RemoveRanFromInstance", RanNameForErrorIndication, E2tAddress).Return(nil)
151         routingManagerClientMock.On("DissociateRanE2TInstance", E2tAddress, RanNameForErrorIndication).Return(nil)
152         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
153
154         
155         handler.Handle(notificationRequest)
156         readerMock.AssertExpectations(t)
157         writerMock.AssertExpectations(t)
158         httpClientMock.AssertExpectations(t)
159         writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
160 }
161 func TestErrorIndicationHandlerWhenConnectedGnbSuccessE2Setup(t *testing.T) {
162         testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationXmlPath)
163 }
164
165 func TestErrorIndicationHandlerWhenConnectedGnbSuccessProcedureType(t *testing.T) {
166         testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationWithoutCDXmlPath)
167 }
168 func TestErrorIndicationHandlerWhenConnectedGnbSuccessServiceUpdate(t *testing.T) {
169         testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t, ErrorIndicationXmlPathServiceUpdate)
170 }
171 func TestErrorIndicationHandlerWhenConnectedGnbSuccessServiceUpdateProcedureType(t *testing.T) {
172         testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t, ErrorIndicationWithoutCDXmlPath)
173 }
174 func TestErrorIndicationHandlerWhenConnectedGnbSuccessUnsuccessfulOutcome(t *testing.T) {
175         testErrorIndicationHandlerWhenConnectedRanSuccess(t, ErrorIndicationXmlPathUnsuccessfuOutcome)
176 }
177 func TestErrorIndicationHandlerInvalidXML(t *testing.T) {
178         testErrorIndicationHandlerInvalidXML(t, ErrorIndicationInvalidXmlPath)
179 }
180 func TestErrorIndicationHandlerForUnknownProcedureType(t *testing.T) {
181         testErrorIndicationHandlerWhenConnectedRanSuccessUnknownProcedureType(t,ErrorIndicationWithoutCDXmlPath)
182 }
183 func TestErrorIndicationHandlerForUnhandlingProcedureType(t *testing.T) {
184         testErrorIndicationHandlerWhenConnectedRanSuccessUnhandlingProcedureType(t,ErrorIndicationWithoutCDXmlPath)
185 }
186 func TestErrorIndicationHandlerForDefaultProcedureCode(t *testing.T) {
187         testErrorIndicationHandlerForDefaultProcedureCode(t,ErrorIndicationXmlPathDefault)
188 }
189 func mockHttpClientForErrorIndication(httpClientMock *mocks.HttpClientMock, isSuccessful bool) {
190         data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2tAddress, RanNameForErrorIndication)}
191         marshaled, _ := json.Marshal(data)
192         body := bytes.NewBuffer(marshaled)
193         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
194         var respStatusCode int
195         if isSuccessful {
196                 respStatusCode = http.StatusCreated
197         } else {
198                 respStatusCode = http.StatusBadRequest
199         }
200         httpClientMock.On("Post", clients.DissociateRanE2TInstanceApiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil).Maybe()
201 }
202
203 func testErrorIndicationHandlerWhenConnectedRanSuccessServiceUpdate(t *testing.T,xmlPath string) {
204         xml := utils.ReadXmlFile(t, xmlPath)
205         handler, readerMock, writerMock, _, _,_, _, _, _, _,_,_ := initErrorIndication(t)
206         origNodebInfo := &entities.NodebInfo{
207                 RanName:                      RanNameForErrorIndication,
208                 GlobalNbId:                   &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"},
209                 ConnectionStatus:             entities.ConnectionStatus_CONNECTED,
210                 AssociatedE2TInstanceAddress: E2tAddress,
211         }
212         logger := tests.InitLog(t)
213         config := &configuration.Configuration{
214                 RnibRetryIntervalMs:       10,
215                 MaxRnibConnectionAttempts: 3,
216                 RnibWriter: configuration.RnibWriterConfig{
217                         StateChangeMessageChannel: StateChangeMessageChannel,
218                 },
219                 GlobalRicId: struct {
220                         RicId string
221                         Mcc   string
222                         Mnc   string
223                 }{Mcc: "327", Mnc: "94", RicId: "AACCE"}}
224         rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
225         RicServiceUpdateManager := managers.NewRicServiceUpdateManager(logger, rnibDataService)
226         models.UpdateProcedureType(RanNameForErrorIndication,models.RicServiceUpdateCompleted)
227
228         var rnibErr error
229         readerMock.On("GetNodeb", RanNameForErrorIndication).Return(origNodebInfo, rnibErr)
230         updatedNodebInfo1 := *origNodebInfo
231         updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_CONNECTED
232         updatedNodebInfo2 := *origNodebInfo
233         updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
234         updatedNodebInfo2.AssociatedE2TInstanceAddress = ""
235         e2tInstance := &entities.E2TInstance{Address: E2tAddress, AssociatedRanList: []string{RanNameForErrorIndication}}
236         readerMock.On("GetE2TInstance", E2tAddress).Return(e2tInstance, nil).Maybe()
237         e2tInstanceToSave := *e2tInstance
238         e2tInstanceToSave.AssociatedRanList = []string{}
239         writerMock.On("UpdateNodebInfoAndPublish", mock.Anything).Return(nil)
240         err := RicServiceUpdateManager.RevertRanFunctions(ranName)
241         assert.Nil(t,err)
242
243         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
244         handler.Handle(notificationRequest)
245         readerMock.AssertExpectations(t)
246         writerMock.AssertExpectations(t)
247 }
248 func testErrorIndicationHandlerWhenConnectedRanSuccessUnknownProcedureType(t *testing.T,xmlPath string) {
249         xml := utils.ReadXmlFile(t, xmlPath)
250         handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t)
251
252         models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureNotInitiated)
253         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
254         handler.Handle(notificationRequest)
255         readerMock.AssertExpectations(t)
256         writerMock.AssertExpectations(t)
257         httpClientMock.AssertExpectations(t)
258 }
259
260 func testErrorIndicationHandlerWhenConnectedRanSuccessUnhandlingProcedureType(t *testing.T,xmlPath string) {
261         xml := utils.ReadXmlFile(t, xmlPath)
262         handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t)
263
264         models.UpdateProcedureType(RanNameForErrorIndication,models.E2SetupProcedureFailure)
265         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
266
267         handler.Handle(notificationRequest)
268         readerMock.AssertExpectations(t)
269         writerMock.AssertExpectations(t)
270         httpClientMock.AssertExpectations(t)
271 }
272
273 func testErrorIndicationHandlerInvalidXML(t *testing.T,xmlPath string) {
274         xml := utils.ReadXmlFile(t, xmlPath)
275         handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t)
276
277         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
278
279         handler.Handle(notificationRequest)
280         readerMock.AssertExpectations(t)
281         writerMock.AssertExpectations(t)
282         httpClientMock.AssertExpectations(t)
283 }
284 func testErrorIndicationHandlerForDefaultProcedureCode(t *testing.T,xmlPath string) {
285         xml := utils.ReadXmlFile(t, xmlPath)
286         handler, readerMock, writerMock, _, _,_, _, _, _, _,httpClientMock,_ := initErrorIndication(t)
287
288         notificationRequest := &models.NotificationRequest{RanName: RanNameForErrorIndication, Payload: append([]byte(e2SetupMsgPrefixErrorIndication), xml...)}
289
290         handler.Handle(notificationRequest)
291         readerMock.AssertExpectations(t)
292         writerMock.AssertExpectations(t)
293         httpClientMock.AssertExpectations(t)
294 }