bc17295a0f18e4fcfefe82bdb7f5182149604c1d
[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         "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"
36         "io/ioutil"
37         "net/http"
38         "testing"
39 )
40
41 const (
42         RanName                   = "test"
43         StateChangeMessageChannel = "RAN_CONNECTION_STATUS_CHANGE"
44 )
45
46 func initE2TAssociationManagerTest(t *testing.T) (*E2TAssociationManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock) {
47         log := initLog(t)
48         config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, RnibWriter: configuration.RnibWriterConfig{ StateChangeMessageChannel: StateChangeMessageChannel}}
49
50         readerMock := &mocks.RnibReaderMock{}
51         writerMock := &mocks.RnibWriterMock{}
52         rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
53
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
62 }
63
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
70         if isSuccessful {
71                 respStatusCode = http.StatusCreated
72         } else {
73                 respStatusCode = http.StatusBadRequest
74         }
75         httpClientMock.On("Post", apiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
76 }
77
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: ""}
82         updatedNb := *nb
83         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
84         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
85         updatedNb2 := *nb
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)
94
95         err := manager.AssociateRan(E2TAddress, nb)
96
97         assert.Nil(t, err)
98         readerMock.AssertExpectations(t)
99         writerMock.AssertExpectations(t)
100         httpClientMock.AssertExpectations(t)
101 }
102
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: ""}
107         updatedNb := *nb
108         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
109         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(common.NewInternalError(fmt.Errorf("for tests")))
110
111         err := manager.AssociateRan(E2TAddress, nb)
112
113         assert.NotNil(t, err)
114         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
115         readerMock.AssertExpectations(t)
116         writerMock.AssertExpectations(t)
117         httpClientMock.AssertExpectations(t)
118 }
119
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)
125
126         err := manager.AssociateRan(E2TAddress, nb)
127
128         assert.NotNil(t, err)
129         assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
130         writerMock.AssertExpectations(t)
131         httpClientMock.AssertExpectations(t)
132 }
133
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: ""}
138
139         updatedNb := *nb
140         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
141         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
142         updatedNb2 := *nb
143         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
144         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
145         writerMock.On("UpdateNodebInfo", &updatedNb2).Return(e2managererrors.NewRnibDbError())
146
147         err := manager.AssociateRan(E2TAddress, nb)
148
149         assert.NotNil(t, err)
150         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
151         readerMock.AssertExpectations(t)
152         writerMock.AssertExpectations(t)
153         httpClientMock.AssertExpectations(t)
154 }
155
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: ""}
160
161         updatedNb := *nb
162         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
163         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(nil)
164
165         updatedNb2 := *nb
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"))
171
172         err := manager.AssociateRan(E2TAddress, nb)
173
174         assert.NotNil(t, err)
175         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
176         readerMock.AssertExpectations(t)
177         writerMock.AssertExpectations(t)
178         httpClientMock.AssertExpectations(t)
179 }
180
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: ""}
185
186         updatedNb := *nb
187         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
188         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, ranName+"_CONNECTED").Return(nil)
189
190         updatedNb2 := *nb
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"))
199
200         err := manager.AssociateRan(E2TAddress, nb)
201
202         assert.NotNil(t, err)
203         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
204         readerMock.AssertExpectations(t)
205         writerMock.AssertExpectations(t)
206         httpClientMock.AssertExpectations(t)
207 }
208
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)
214         updatedNb := *nb
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)
223
224         err := manager.DissociateRan(E2TAddress, RanName)
225
226         assert.Nil(t, err)
227         readerMock.AssertExpectations(t)
228         writerMock.AssertExpectations(t)
229         httpClientMock.AssertExpectations(t)
230 }
231
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())
236
237         err := manager.DissociateRan(E2TAddress, RanName)
238
239         assert.NotNil(t, err)
240         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
241         readerMock.AssertExpectations(t)
242         writerMock.AssertExpectations(t)
243         httpClientMock.AssertExpectations(t)
244 }
245
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)
250         updatedNb := *nb
251         updatedNb.AssociatedE2TInstanceAddress = ""
252         writerMock.On("UpdateNodebInfo", &updatedNb).Return(e2managererrors.NewRnibDbError())
253
254         err := manager.DissociateRan(E2TAddress, RanName)
255
256         assert.NotNil(t, err)
257         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
258         readerMock.AssertExpectations(t)
259         writerMock.AssertExpectations(t)
260         httpClientMock.AssertExpectations(t)
261 }
262
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)
267         updatedNb := *nb
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"))
272
273         err := manager.DissociateRan(E2TAddress, RanName)
274
275         assert.NotNil(t, err)
276         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
277         readerMock.AssertExpectations(t)
278         writerMock.AssertExpectations(t)
279         httpClientMock.AssertExpectations(t)
280 }
281
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)
286         updatedNb := *nb
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"))
295
296         err := manager.DissociateRan(E2TAddress, RanName)
297
298         assert.NotNil(t, err)
299         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
300         readerMock.AssertExpectations(t)
301         writerMock.AssertExpectations(t)
302         httpClientMock.AssertExpectations(t)
303 }
304
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)
310         updatedNb := *nb
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)
319
320         err := manager.DissociateRan(E2TAddress, RanName)
321
322         assert.Nil(t, err)
323         readerMock.AssertExpectations(t)
324         writerMock.AssertExpectations(t)
325         httpClientMock.AssertExpectations(t)
326 }
327
328 func TestRemoveE2tInstanceSuccessWithOrphans(t *testing.T) {
329         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
330
331         ranNamesToBeDissociated := []string{RanName, "test1"}
332         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, ranNamesToBeDissociated, nil)
333         mockHttpClientDelete(httpClientMock, data, true)
334
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)
340
341         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: ranNamesToBeDissociated}
342         err := manager.RemoveE2tInstance(e2tInstance1)
343
344         assert.Nil(t, err)
345         readerMock.AssertExpectations(t)
346         writerMock.AssertExpectations(t)
347         httpClientMock.AssertExpectations(t)
348 }
349
350 func TestRemoveE2tInstanceFailureRoutingManager(t *testing.T) {
351         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
352
353         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
354         mockHttpClientDelete(httpClientMock, data, false)
355
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)
361
362         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
363         //readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewRnibDbError())
364         err := manager.RemoveE2tInstance(e2tInstance1)
365
366         assert.Nil(t, err)
367         readerMock.AssertExpectations(t)
368         writerMock.AssertExpectations(t)
369         httpClientMock.AssertExpectations(t)
370 }
371
372 func TestRemoveE2tInstanceFailureInE2TInstanceManager(t *testing.T) {
373
374         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
375         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
376         mockHttpClientDelete(httpClientMock, data, true)
377
378         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
379         var e2tAddresses []string
380         readerMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
381
382         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1"}}
383         err := manager.RemoveE2tInstance(e2tInstance1)
384
385         assert.NotNil(t, err)
386         readerMock.AssertExpectations(t)
387         writerMock.AssertExpectations(t)
388         httpClientMock.AssertExpectations(t)
389 }
390
391 func TestRemoveE2tInstanceFailureInE2tInstanceAddRansToInstance(t *testing.T) {
392         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
393
394         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
395         mockHttpClientDelete(httpClientMock, data, true)
396
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)
402
403         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress}
404         err := manager.RemoveE2tInstance(e2tInstance1)
405
406         assert.Nil(t, err)
407         readerMock.AssertExpectations(t)
408         writerMock.AssertExpectations(t)
409         httpClientMock.AssertExpectations(t)
410 }
411
412 func mockHttpClientDelete(httpClientMock *mocks.HttpClientMock, data *models.RoutingManagerDeleteRequestModel, isSuccessful bool) {
413
414         marshaled, _ := json.Marshal(data)
415         body := bytes.NewBuffer(marshaled)
416         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
417         var respStatusCode int
418         if isSuccessful {
419                 respStatusCode = http.StatusCreated
420         } else {
421                 respStatusCode = http.StatusBadRequest
422         }
423         httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
424 }