RIC916 new reconnect timer in E2 to reject new connect for x seconds
[ric-plt/e2mgr.git] / E2Manager / managers / e2t_association_manager_test.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 //
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
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16
17 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 //  platform project (RICP).
19
20 package managers
21
22 import (
23         "bytes"
24         "e2mgr/clients"
25         "e2mgr/configuration"
26         "e2mgr/e2managererrors"
27         "e2mgr/mocks"
28         "e2mgr/models"
29         "e2mgr/services"
30         "encoding/json"
31         "fmt"
32         "io/ioutil"
33         "net/http"
34         "testing"
35
36         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
37         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
38         "github.com/pkg/errors"
39         "github.com/stretchr/testify/assert"
40         "github.com/stretchr/testify/mock"
41 )
42
43 const (
44         RanName                   = "test"
45         StateChangeMessageChannel = "RAN_CONNECTION_STATUS_CHANGE"
46 )
47
48 func initE2TAssociationManagerTest(t *testing.T) (*E2TAssociationManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock) {
49         log := initLog(t)
50         config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, RnibWriter: configuration.RnibWriterConfig{StateChangeMessageChannel: StateChangeMessageChannel}}
51
52         readerMock := &mocks.RnibReaderMock{}
53         writerMock := &mocks.RnibWriterMock{}
54         rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
55
56         e2tInstancesManager := NewE2TInstancesManager(rnibDataService, log)
57         httpClientMock := &mocks.HttpClientMock{}
58         rmClient := clients.NewRoutingManagerClient(log, config, httpClientMock)
59         ranListManager := NewRanListManager(log, rnibDataService)
60         ranAlarmService := services.NewRanAlarmService(log, config)
61         ranConnectStatusChangeManager := NewRanConnectStatusChangeManager(log, rnibDataService, ranListManager, ranAlarmService)
62         e2tAssociationManager := NewE2TAssociationManager(log, rnibDataService, e2tInstancesManager, rmClient, ranConnectStatusChangeManager)
63         return e2tAssociationManager, readerMock, writerMock, httpClientMock
64 }
65
66 func mockHttpClient(httpClientMock *mocks.HttpClientMock, apiSuffix string, isSuccessful bool) {
67         data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2TAddress, RanName)}
68         marshaled, _ := json.Marshal(data)
69         body := bytes.NewBuffer(marshaled)
70         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
71         var respStatusCode int
72         if isSuccessful {
73                 respStatusCode = http.StatusCreated
74         } else {
75                 respStatusCode = http.StatusBadRequest
76         }
77         httpClientMock.On("Post", apiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
78 }
79
80 func TestAssociateRanSuccess(t *testing.T) {
81         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
82         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
83         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
84         updatedNb := *nb
85         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
86         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanName+"_CONNECTED").Return(nil)
87         updatedNb2 := *nb
88         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
89         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
90         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
91         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
92         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
93         updatedE2tInstance := *e2tInstance
94         updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
95         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
96
97         _, err := manager.AssociateRan(E2TAddress, nb)
98
99         assert.Nil(t, err)
100         readerMock.AssertExpectations(t)
101         writerMock.AssertExpectations(t)
102         httpClientMock.AssertExpectations(t)
103 }
104
105 func TestAssociateRan_RnibError(t *testing.T) {
106         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
107         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
108         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
109         updatedNb := *nb
110         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
111         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanName+"_CONNECTED").Return(common.NewInternalError(fmt.Errorf("for tests")))
112
113         _, err := manager.AssociateRan(E2TAddress, nb)
114
115         assert.NotNil(t, err)
116         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
117         readerMock.AssertExpectations(t)
118         writerMock.AssertExpectations(t)
119         httpClientMock.AssertExpectations(t)
120 }
121
122 func TestAssociateRanRoutingManagerError(t *testing.T) {
123         manager, _, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
124         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, false)
125         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
126         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
127
128         _, err := manager.AssociateRan(E2TAddress, nb)
129
130         assert.NotNil(t, err)
131         assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
132         writerMock.AssertExpectations(t)
133         httpClientMock.AssertExpectations(t)
134 }
135
136 func TestAssociateRanUpdateNodebError(t *testing.T) {
137         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
138         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
139         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
140
141         updatedNb := *nb
142         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
143         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanName+"_CONNECTED").Return(nil)
144         updatedNb2 := *nb
145         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
146         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
147         writerMock.On("UpdateNodebInfo", mock.Anything).Return(e2managererrors.NewRnibDbError())
148
149         _, err := manager.AssociateRan(E2TAddress, nb)
150
151         assert.NotNil(t, err)
152         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
153         readerMock.AssertExpectations(t)
154         writerMock.AssertExpectations(t)
155         httpClientMock.AssertExpectations(t)
156 }
157
158 func TestAssociateRanGetE2tInstanceError(t *testing.T) {
159         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
160         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
161         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
162
163         updatedNb := *nb
164         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
165         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, RanName+"_CONNECTED").Return(nil)
166
167         updatedNb2 := *nb
168         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
169         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
170         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
171         var e2tInstance *entities.E2TInstance
172         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
173
174         _, err := manager.AssociateRan(E2TAddress, nb)
175
176         assert.NotNil(t, err)
177         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
178         readerMock.AssertExpectations(t)
179         writerMock.AssertExpectations(t)
180         httpClientMock.AssertExpectations(t)
181 }
182
183 func TestAssociateRanSaveE2tInstanceError(t *testing.T) {
184         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
185         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
186         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
187
188         updatedNb := *nb
189         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
190         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", mock.Anything, ranName+"_CONNECTED").Return(nil)
191
192         updatedNb2 := *nb
193         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
194         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
195         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
196         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
197         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
198         updatedE2tInstance := *e2tInstance
199         updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
200         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
201
202         _, err := manager.AssociateRan(E2TAddress, nb)
203
204         assert.NotNil(t, err)
205         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
206         readerMock.AssertExpectations(t)
207         writerMock.AssertExpectations(t)
208         httpClientMock.AssertExpectations(t)
209 }
210
211 func TestDissociateRanSuccess(t *testing.T) {
212         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
213         mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, true)
214         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
215         readerMock.On("GetNodeb", RanName).Return(nb, nil)
216         updatedNb := *nb
217         updatedNb.AssociatedE2TInstanceAddress = ""
218         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
219         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
220         e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
221         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
222         updatedE2tInstance := *e2tInstance
223         updatedE2tInstance.AssociatedRanList = []string{}
224         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
225
226         err := manager.DissociateRan(E2TAddress, RanName)
227
228         assert.Nil(t, err)
229         readerMock.AssertExpectations(t)
230         writerMock.AssertExpectations(t)
231         httpClientMock.AssertExpectations(t)
232 }
233
234 func TestDissociateRanGetNodebError(t *testing.T) {
235         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
236         var nb *entities.NodebInfo
237         readerMock.On("GetNodeb", RanName).Return(nb, e2managererrors.NewRnibDbError())
238
239         err := manager.DissociateRan(E2TAddress, RanName)
240
241         assert.NotNil(t, err)
242         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
243         readerMock.AssertExpectations(t)
244         writerMock.AssertExpectations(t)
245         httpClientMock.AssertExpectations(t)
246 }
247
248 func TestDissociateRanUpdateNodebError(t *testing.T) {
249         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
250         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
251         readerMock.On("GetNodeb", RanName).Return(nb, nil)
252         updatedNb := *nb
253         updatedNb.AssociatedE2TInstanceAddress = ""
254         writerMock.On("UpdateNodebInfo", mock.Anything).Return(e2managererrors.NewRnibDbError())
255
256         err := manager.DissociateRan(E2TAddress, RanName)
257
258         assert.NotNil(t, err)
259         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
260         readerMock.AssertExpectations(t)
261         writerMock.AssertExpectations(t)
262         httpClientMock.AssertExpectations(t)
263 }
264
265 func TestDissociateRanGetE2tInstanceError(t *testing.T) {
266         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
267         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
268         readerMock.On("GetNodeb", RanName).Return(nb, nil)
269         updatedNb := *nb
270         updatedNb.AssociatedE2TInstanceAddress = ""
271         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
272         var e2tInstance *entities.E2TInstance
273         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
274
275         err := manager.DissociateRan(E2TAddress, RanName)
276
277         assert.NotNil(t, err)
278         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
279         readerMock.AssertExpectations(t)
280         writerMock.AssertExpectations(t)
281         httpClientMock.AssertExpectations(t)
282 }
283
284 func TestDissociateRanSaveE2tInstanceError(t *testing.T) {
285         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
286         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
287         readerMock.On("GetNodeb", RanName).Return(nb, nil)
288         updatedNb := *nb
289         updatedNb.AssociatedE2TInstanceAddress = ""
290         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
291         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
292         e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
293         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
294         updatedE2tInstance := *e2tInstance
295         updatedE2tInstance.AssociatedRanList = []string{}
296         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
297
298         err := manager.DissociateRan(E2TAddress, RanName)
299
300         assert.NotNil(t, err)
301         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
302         readerMock.AssertExpectations(t)
303         writerMock.AssertExpectations(t)
304         httpClientMock.AssertExpectations(t)
305 }
306
307 func TestDissociateRanRoutingManagerError(t *testing.T) {
308         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
309         mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, false)
310         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
311         readerMock.On("GetNodeb", RanName).Return(nb, nil)
312         updatedNb := *nb
313         updatedNb.AssociatedE2TInstanceAddress = ""
314         writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil)
315         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
316         e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
317         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
318         updatedE2tInstance := *e2tInstance
319         updatedE2tInstance.AssociatedRanList = []string{}
320         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
321
322         err := manager.DissociateRan(E2TAddress, RanName)
323
324         assert.Nil(t, err)
325         readerMock.AssertExpectations(t)
326         writerMock.AssertExpectations(t)
327         httpClientMock.AssertExpectations(t)
328 }
329
330 func TestRemoveE2tInstanceSuccessWithOrphans(t *testing.T) {
331         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
332
333         ranNamesToBeDissociated := []string{RanName, "test1"}
334         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, ranNamesToBeDissociated, nil)
335         mockHttpClientDelete(httpClientMock, data, true)
336
337         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
338         e2tAddresses := []string{E2TAddress}
339         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
340         e2tAddressesNew := []string{}
341         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
342
343         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: ranNamesToBeDissociated}
344         err := manager.RemoveE2tInstance(e2tInstance1)
345
346         assert.Nil(t, err)
347         readerMock.AssertExpectations(t)
348         writerMock.AssertExpectations(t)
349         httpClientMock.AssertExpectations(t)
350 }
351
352 func TestRemoveE2tInstanceFailureRoutingManager(t *testing.T) {
353         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
354
355         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
356         mockHttpClientDelete(httpClientMock, data, false)
357
358         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
359         e2tAddresses := []string{E2TAddress}
360         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
361         e2tAddressesNew := []string{}
362         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
363
364         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
365         //readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewRnibDbError())
366         err := manager.RemoveE2tInstance(e2tInstance1)
367
368         assert.Nil(t, err)
369         readerMock.AssertExpectations(t)
370         writerMock.AssertExpectations(t)
371         httpClientMock.AssertExpectations(t)
372 }
373
374 func TestRemoveE2tInstanceFailureInE2TInstanceManager(t *testing.T) {
375
376         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
377         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
378         mockHttpClientDelete(httpClientMock, data, true)
379
380         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
381         var e2tAddresses []string
382         readerMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
383
384         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
385         err := manager.RemoveE2tInstance(e2tInstance1)
386
387         assert.NotNil(t, err)
388         readerMock.AssertExpectations(t)
389         writerMock.AssertExpectations(t)
390         httpClientMock.AssertExpectations(t)
391 }
392
393 func TestRemoveE2tInstanceFailureInE2tInstanceAddRansToInstance(t *testing.T) {
394         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
395
396         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
397         mockHttpClientDelete(httpClientMock, data, true)
398
399         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
400         e2tAddresses := []string{E2TAddress, E2TAddress2, E2TAddress3}
401         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
402         e2tAddressesNew := []string{E2TAddress2, E2TAddress3}
403         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
404
405         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress}
406         err := manager.RemoveE2tInstance(e2tInstance1)
407
408         assert.Nil(t, err)
409         readerMock.AssertExpectations(t)
410         writerMock.AssertExpectations(t)
411         httpClientMock.AssertExpectations(t)
412 }
413
414 func mockHttpClientDelete(httpClientMock *mocks.HttpClientMock, data *models.RoutingManagerDeleteRequestModel, isSuccessful bool) {
415
416         marshaled, _ := json.Marshal(data)
417         body := bytes.NewBuffer(marshaled)
418         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
419         var respStatusCode int
420         if isSuccessful {
421                 respStatusCode = http.StatusCreated
422         } else {
423                 respStatusCode = http.StatusBadRequest
424         }
425         httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
426 }