2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 // This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 // platform project (RICP).
26 "e2mgr/e2managererrors"
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/pkg/errors"
35 "github.com/stretchr/testify/assert"
43 StateChangeMessageChannel = "RAN_CONNECTION_STATUS_CHANGE"
46 func initE2TAssociationManagerTest(t *testing.T) (*E2TAssociationManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock) {
48 config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, RnibWriter: configuration.RnibWriterConfig{ StateChangeMessageChannel: StateChangeMessageChannel}}
50 readerMock := &mocks.RnibReaderMock{}
51 writerMock := &mocks.RnibWriterMock{}
52 rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
54 e2tInstancesManager := NewE2TInstancesManager(rnibDataService, log)
55 httpClientMock := &mocks.HttpClientMock{}
56 rmClient := clients.NewRoutingManagerClient(log, config, httpClientMock)
57 ranListManager := NewRanListManager(log, rnibDataService)
58 ranAlarmService := services.NewRanAlarmService(log, config)
59 ranConnectStatusChangeManager := NewRanConnectStatusChangeManager(log, rnibDataService, ranListManager, ranAlarmService)
60 e2tAssociationManager := NewE2TAssociationManager(log, rnibDataService, e2tInstancesManager, rmClient, ranConnectStatusChangeManager)
61 return e2tAssociationManager, readerMock, writerMock, httpClientMock
64 func mockHttpClient(httpClientMock *mocks.HttpClientMock, apiSuffix string, isSuccessful bool) {
65 data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2TAddress, RanName)}
66 marshaled, _ := json.Marshal(data)
67 body := bytes.NewBuffer(marshaled)
68 respBody := ioutil.NopCloser(bytes.NewBufferString(""))
69 var respStatusCode int
71 respStatusCode = http.StatusCreated
73 respStatusCode = http.StatusBadRequest
75 httpClientMock.On("Post", apiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
78 func TestAssociateRanSuccess(t *testing.T) {
79 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
80 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
81 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
83 updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
84 writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
86 updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
87 updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
88 writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
89 e2tInstance := &entities.E2TInstance{Address: E2TAddress}
90 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
91 updatedE2tInstance := *e2tInstance
92 updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
93 writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
95 err := manager.AssociateRan(E2TAddress, nb)
98 readerMock.AssertExpectations(t)
99 writerMock.AssertExpectations(t)
100 httpClientMock.AssertExpectations(t)
103 func TestAssociateRan_RnibError(t *testing.T) {
104 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
105 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
106 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
108 updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
109 writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(common.NewInternalError(fmt.Errorf("for tests")))
111 err := manager.AssociateRan(E2TAddress, nb)
113 assert.NotNil(t, err)
114 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
115 readerMock.AssertExpectations(t)
116 writerMock.AssertExpectations(t)
117 httpClientMock.AssertExpectations(t)
120 func TestAssociateRanRoutingManagerError(t *testing.T) {
121 manager, _, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
122 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, false)
123 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
124 writerMock.On("UpdateNodebInfo", nb).Return(nil)
126 err := manager.AssociateRan(E2TAddress, nb)
128 assert.NotNil(t, err)
129 assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
130 writerMock.AssertExpectations(t)
131 httpClientMock.AssertExpectations(t)
134 func TestAssociateRanUpdateNodebError(t *testing.T) {
135 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
136 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
137 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
140 updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
141 writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
143 updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
144 updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
145 writerMock.On("UpdateNodebInfo", &updatedNb2).Return(e2managererrors.NewRnibDbError())
147 err := manager.AssociateRan(E2TAddress, nb)
149 assert.NotNil(t, err)
150 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
151 readerMock.AssertExpectations(t)
152 writerMock.AssertExpectations(t)
153 httpClientMock.AssertExpectations(t)
156 func TestAssociateRanGetE2tInstanceError(t *testing.T) {
157 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
158 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
159 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
162 updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
163 writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
166 updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
167 updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
168 writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
169 var e2tInstance *entities.E2TInstance
170 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
172 err := manager.AssociateRan(E2TAddress, nb)
174 assert.NotNil(t, err)
175 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
176 readerMock.AssertExpectations(t)
177 writerMock.AssertExpectations(t)
178 httpClientMock.AssertExpectations(t)
181 func TestAssociateRanSaveE2tInstanceError(t *testing.T) {
182 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
183 mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
184 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
187 updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
188 writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, ranName+"_CONNECTED").Return(nil)
191 updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
192 updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
193 writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
194 e2tInstance := &entities.E2TInstance{Address: E2TAddress}
195 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
196 updatedE2tInstance := *e2tInstance
197 updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
198 writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
200 err := manager.AssociateRan(E2TAddress, nb)
202 assert.NotNil(t, err)
203 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
204 readerMock.AssertExpectations(t)
205 writerMock.AssertExpectations(t)
206 httpClientMock.AssertExpectations(t)
209 func TestDissociateRanSuccess(t *testing.T) {
210 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
211 mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, true)
212 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
213 readerMock.On("GetNodeb", RanName).Return(nb, nil)
215 updatedNb.AssociatedE2TInstanceAddress = ""
216 writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
217 e2tInstance := &entities.E2TInstance{Address: E2TAddress}
218 e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
219 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
220 updatedE2tInstance := *e2tInstance
221 updatedE2tInstance.AssociatedRanList = []string{}
222 writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
224 err := manager.DissociateRan(E2TAddress, RanName)
227 readerMock.AssertExpectations(t)
228 writerMock.AssertExpectations(t)
229 httpClientMock.AssertExpectations(t)
232 func TestDissociateRanGetNodebError(t *testing.T) {
233 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
234 var nb *entities.NodebInfo
235 readerMock.On("GetNodeb", RanName).Return(nb, e2managererrors.NewRnibDbError())
237 err := manager.DissociateRan(E2TAddress, RanName)
239 assert.NotNil(t, err)
240 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
241 readerMock.AssertExpectations(t)
242 writerMock.AssertExpectations(t)
243 httpClientMock.AssertExpectations(t)
246 func TestDissociateRanUpdateNodebError(t *testing.T) {
247 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
248 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
249 readerMock.On("GetNodeb", RanName).Return(nb, nil)
251 updatedNb.AssociatedE2TInstanceAddress = ""
252 writerMock.On("UpdateNodebInfo", &updatedNb).Return(e2managererrors.NewRnibDbError())
254 err := manager.DissociateRan(E2TAddress, RanName)
256 assert.NotNil(t, err)
257 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
258 readerMock.AssertExpectations(t)
259 writerMock.AssertExpectations(t)
260 httpClientMock.AssertExpectations(t)
263 func TestDissociateRanGetE2tInstanceError(t *testing.T) {
264 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
265 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
266 readerMock.On("GetNodeb", RanName).Return(nb, nil)
268 updatedNb.AssociatedE2TInstanceAddress = ""
269 writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
270 var e2tInstance *entities.E2TInstance
271 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
273 err := manager.DissociateRan(E2TAddress, RanName)
275 assert.NotNil(t, err)
276 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
277 readerMock.AssertExpectations(t)
278 writerMock.AssertExpectations(t)
279 httpClientMock.AssertExpectations(t)
282 func TestDissociateRanSaveE2tInstanceError(t *testing.T) {
283 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
284 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
285 readerMock.On("GetNodeb", RanName).Return(nb, nil)
287 updatedNb.AssociatedE2TInstanceAddress = ""
288 writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
289 e2tInstance := &entities.E2TInstance{Address: E2TAddress}
290 e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
291 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
292 updatedE2tInstance := *e2tInstance
293 updatedE2tInstance.AssociatedRanList = []string{}
294 writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
296 err := manager.DissociateRan(E2TAddress, RanName)
298 assert.NotNil(t, err)
299 assert.IsType(t, &e2managererrors.RnibDbError{}, err)
300 readerMock.AssertExpectations(t)
301 writerMock.AssertExpectations(t)
302 httpClientMock.AssertExpectations(t)
305 func TestDissociateRanRoutingManagerError(t *testing.T) {
306 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
307 mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, false)
308 nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
309 readerMock.On("GetNodeb", RanName).Return(nb, nil)
311 updatedNb.AssociatedE2TInstanceAddress = ""
312 writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
313 e2tInstance := &entities.E2TInstance{Address: E2TAddress}
314 e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
315 readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
316 updatedE2tInstance := *e2tInstance
317 updatedE2tInstance.AssociatedRanList = []string{}
318 writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
320 err := manager.DissociateRan(E2TAddress, RanName)
323 readerMock.AssertExpectations(t)
324 writerMock.AssertExpectations(t)
325 httpClientMock.AssertExpectations(t)
328 func TestRemoveE2tInstanceSuccessWithOrphans(t *testing.T) {
329 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
331 ranNamesToBeDissociated := []string{RanName, "test1"}
332 data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, ranNamesToBeDissociated, nil)
333 mockHttpClientDelete(httpClientMock, data, true)
335 writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
336 e2tAddresses := []string{E2TAddress}
337 readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
338 e2tAddressesNew := []string{}
339 writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
341 e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: ranNamesToBeDissociated}
342 err := manager.RemoveE2tInstance(e2tInstance1)
345 readerMock.AssertExpectations(t)
346 writerMock.AssertExpectations(t)
347 httpClientMock.AssertExpectations(t)
350 func TestRemoveE2tInstanceFailureRoutingManager(t *testing.T) {
351 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
353 data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
354 mockHttpClientDelete(httpClientMock, data, false)
356 writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
357 e2tAddresses := []string{E2TAddress}
358 readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
359 e2tAddressesNew := []string{}
360 writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
362 e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
363 //readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewRnibDbError())
364 err := manager.RemoveE2tInstance(e2tInstance1)
367 readerMock.AssertExpectations(t)
368 writerMock.AssertExpectations(t)
369 httpClientMock.AssertExpectations(t)
372 func TestRemoveE2tInstanceFailureInE2TInstanceManager(t *testing.T) {
374 data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
375 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
376 mockHttpClientDelete(httpClientMock, data, true)
378 writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
379 var e2tAddresses []string
380 readerMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
382 e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
383 err := manager.RemoveE2tInstance(e2tInstance1)
385 assert.NotNil(t, err)
386 readerMock.AssertExpectations(t)
387 writerMock.AssertExpectations(t)
388 httpClientMock.AssertExpectations(t)
391 func TestRemoveE2tInstanceFailureInE2tInstanceAddRansToInstance(t *testing.T) {
392 manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
394 data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
395 mockHttpClientDelete(httpClientMock, data, true)
397 writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
398 e2tAddresses := []string{E2TAddress, E2TAddress2, E2TAddress3}
399 readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
400 e2tAddressesNew := []string{E2TAddress2, E2TAddress3}
401 writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
403 e2tInstance1 := &entities.E2TInstance{Address: E2TAddress}
404 err := manager.RemoveE2tInstance(e2tInstance1)
407 readerMock.AssertExpectations(t)
408 writerMock.AssertExpectations(t)
409 httpClientMock.AssertExpectations(t)
412 func mockHttpClientDelete(httpClientMock *mocks.HttpClientMock, data *models.RoutingManagerDeleteRequestModel, isSuccessful bool) {
414 marshaled, _ := json.Marshal(data)
415 body := bytes.NewBuffer(marshaled)
416 respBody := ioutil.NopCloser(bytes.NewBufferString(""))
417 var respStatusCode int
419 respStatusCode = http.StatusCreated
421 respStatusCode = http.StatusBadRequest
423 httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)