[RIC-475] [RIC-507] Inject RanStatusChangeManager | Enhance E2 Setup flow | Remove...
[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         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
32         "github.com/pkg/errors"
33         "github.com/stretchr/testify/assert"
34         "io/ioutil"
35         "net/http"
36         "testing"
37 )
38
39 const RanName = "test"
40
41 func initE2TAssociationManagerTest(t *testing.T) (*E2TAssociationManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock) {
42         log := initLog(t)
43         config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, StateChangeMessageChannel: "RAN_CONNECTION_STATUS_CHANGE"}
44
45         readerMock := &mocks.RnibReaderMock{}
46         writerMock := &mocks.RnibWriterMock{}
47         rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
48
49         e2tInstancesManager := NewE2TInstancesManager(rnibDataService, log)
50         httpClientMock := &mocks.HttpClientMock{}
51         rmClient := clients.NewRoutingManagerClient(log, config, httpClientMock)
52         ranListManager := NewRanListManager(log)
53         ranAlarmService := services.NewRanAlarmService(log, config)
54         ranConnectStatusChangeManager := NewRanConnectStatusChangeManager(log, rnibDataService,ranListManager, ranAlarmService)
55         e2tAssociationManager := NewE2TAssociationManager(log, rnibDataService, e2tInstancesManager, rmClient, ranConnectStatusChangeManager)
56         return e2tAssociationManager, readerMock, writerMock, httpClientMock
57 }
58
59 func mockHttpClient(httpClientMock *mocks.HttpClientMock, apiSuffix string, isSuccessful bool) {
60         data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2TAddress, RanName)}
61         marshaled, _ := json.Marshal(data)
62         body := bytes.NewBuffer(marshaled)
63         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
64         var respStatusCode int
65         if isSuccessful {
66                 respStatusCode = http.StatusCreated
67         } else {
68                 respStatusCode = http.StatusBadRequest
69         }
70         httpClientMock.On("Post", apiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
71 }
72
73 func TestAssociateRanSuccess(t *testing.T) {
74         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
75         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
76         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
77         updatedNb := *nb
78         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
79         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, "RAN_CONNECTION_STATUS_CHANGE", RanName+"_CONNECTED").Return(nil)
80         updatedNb2 := *nb
81         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
82         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
83         writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
84         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
85         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
86         updatedE2tInstance := *e2tInstance
87         updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
88         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
89
90         err := manager.AssociateRan(E2TAddress, nb)
91
92         assert.Nil(t, err)
93         readerMock.AssertExpectations(t)
94         writerMock.AssertExpectations(t)
95         httpClientMock.AssertExpectations(t)
96 }
97
98 func TestAssociateRanRoutingManagerError(t *testing.T) {
99         manager, _, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
100         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, false)
101         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
102         writerMock.On("UpdateNodebInfo", nb).Return(nil)
103
104         err := manager.AssociateRan(E2TAddress, nb)
105
106         assert.NotNil(t, err)
107         assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
108         writerMock.AssertExpectations(t)
109         httpClientMock.AssertExpectations(t)
110 }
111
112 func TestAssociateRanUpdateNodebError(t *testing.T) {
113         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
114         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
115         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
116
117         updatedNb := *nb
118         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
119         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, "RAN_CONNECTION_STATUS_CHANGE", RanName+"_CONNECTED").Return(nil)
120         updatedNb2 := *nb
121         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
122         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
123         writerMock.On("UpdateNodebInfo", &updatedNb2).Return(e2managererrors.NewRnibDbError())
124
125         err := manager.AssociateRan(E2TAddress, nb)
126
127         assert.NotNil(t, err)
128         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
129         readerMock.AssertExpectations(t)
130         writerMock.AssertExpectations(t)
131         httpClientMock.AssertExpectations(t)
132 }
133
134 func TestAssociateRanGetE2tInstanceError(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, "RAN_CONNECTION_STATUS_CHANGE", RanName+"_CONNECTED").Return(nil)
142
143         updatedNb2 := *nb
144         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
145         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
146         writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
147         var e2tInstance *entities.E2TInstance
148         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
149
150         err := manager.AssociateRan(E2TAddress, nb)
151
152         assert.NotNil(t, err)
153         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
154         readerMock.AssertExpectations(t)
155         writerMock.AssertExpectations(t)
156         httpClientMock.AssertExpectations(t)
157 }
158
159 func TestAssociateRanSaveE2tInstanceError(t *testing.T) {
160         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
161         mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
162         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
163
164         updatedNb := *nb
165         updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
166         writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, "RAN_CONNECTION_STATUS_CHANGE", RanName+"_CONNECTED").Return(nil)
167
168         updatedNb2 := *nb
169         updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
170         updatedNb2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
171         writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil)
172         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
173         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
174         updatedE2tInstance := *e2tInstance
175         updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
176         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
177
178         err := manager.AssociateRan(E2TAddress, nb)
179
180         assert.NotNil(t, err)
181         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
182         readerMock.AssertExpectations(t)
183         writerMock.AssertExpectations(t)
184         httpClientMock.AssertExpectations(t)
185 }
186
187 func TestDissociateRanSuccess(t *testing.T) {
188         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
189         mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, true)
190         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
191         readerMock.On("GetNodeb", RanName).Return(nb, nil)
192         updatedNb := *nb
193         updatedNb.AssociatedE2TInstanceAddress = ""
194         writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
195         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
196         e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
197         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
198         updatedE2tInstance := *e2tInstance
199         updatedE2tInstance.AssociatedRanList = []string{}
200         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
201
202         err := manager.DissociateRan(E2TAddress, RanName)
203
204         assert.Nil(t, err)
205         readerMock.AssertExpectations(t)
206         writerMock.AssertExpectations(t)
207         httpClientMock.AssertExpectations(t)
208 }
209
210 func TestDissociateRanGetNodebError(t *testing.T) {
211         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
212         var nb *entities.NodebInfo
213         readerMock.On("GetNodeb", RanName).Return(nb, e2managererrors.NewRnibDbError())
214
215         err := manager.DissociateRan(E2TAddress, RanName)
216
217         assert.NotNil(t, err)
218         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
219         readerMock.AssertExpectations(t)
220         writerMock.AssertExpectations(t)
221         httpClientMock.AssertExpectations(t)
222 }
223
224 func TestDissociateRanUpdateNodebError(t *testing.T) {
225         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
226         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
227         readerMock.On("GetNodeb", RanName).Return(nb, nil)
228         updatedNb := *nb
229         updatedNb.AssociatedE2TInstanceAddress = ""
230         writerMock.On("UpdateNodebInfo", &updatedNb).Return(e2managererrors.NewRnibDbError())
231
232         err := manager.DissociateRan(E2TAddress, RanName)
233
234         assert.NotNil(t, err)
235         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
236         readerMock.AssertExpectations(t)
237         writerMock.AssertExpectations(t)
238         httpClientMock.AssertExpectations(t)
239 }
240
241 func TestDissociateRanGetE2tInstanceError(t *testing.T) {
242         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
243         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
244         readerMock.On("GetNodeb", RanName).Return(nb, nil)
245         updatedNb := *nb
246         updatedNb.AssociatedE2TInstanceAddress = ""
247         writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
248         var e2tInstance *entities.E2TInstance
249         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
250
251         err := manager.DissociateRan(E2TAddress, RanName)
252
253         assert.NotNil(t, err)
254         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
255         readerMock.AssertExpectations(t)
256         writerMock.AssertExpectations(t)
257         httpClientMock.AssertExpectations(t)
258 }
259
260 func TestDissociateRanSaveE2tInstanceError(t *testing.T) {
261         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
262         nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
263         readerMock.On("GetNodeb", RanName).Return(nb, nil)
264         updatedNb := *nb
265         updatedNb.AssociatedE2TInstanceAddress = ""
266         writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
267         e2tInstance := &entities.E2TInstance{Address: E2TAddress}
268         e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
269         readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
270         updatedE2tInstance := *e2tInstance
271         updatedE2tInstance.AssociatedRanList = []string{}
272         writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
273
274         err := manager.DissociateRan(E2TAddress, RanName)
275
276         assert.NotNil(t, err)
277         assert.IsType(t, &e2managererrors.RnibDbError{}, err)
278         readerMock.AssertExpectations(t)
279         writerMock.AssertExpectations(t)
280         httpClientMock.AssertExpectations(t)
281 }
282
283 func TestDissociateRanRoutingManagerError(t *testing.T) {
284         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
285         mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, false)
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", &updatedNb).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(nil)
297
298         err := manager.DissociateRan(E2TAddress, RanName)
299
300         assert.Nil(t, err)
301         readerMock.AssertExpectations(t)
302         writerMock.AssertExpectations(t)
303         httpClientMock.AssertExpectations(t)
304 }
305
306 func TestRemoveE2tInstanceSuccessWithOrphans(t *testing.T) {
307         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
308
309         ranNamesToBeDissociated := []string{RanName, "test1"}
310         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, ranNamesToBeDissociated, nil)
311         mockHttpClientDelete(httpClientMock, data, true)
312
313         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
314         e2tAddresses := []string{E2TAddress}
315         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
316         e2tAddressesNew := []string{}
317         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
318
319         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:ranNamesToBeDissociated}
320         err := manager.RemoveE2tInstance(e2tInstance1)
321
322         assert.Nil(t, err)
323         readerMock.AssertExpectations(t)
324         writerMock.AssertExpectations(t)
325         httpClientMock.AssertExpectations(t)
326 }
327
328 func TestRemoveE2tInstanceFailureRoutingManager(t *testing.T) {
329         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
330
331         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
332         mockHttpClientDelete(httpClientMock, data, false)
333
334         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
335         e2tAddresses := []string{E2TAddress}
336         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
337         e2tAddressesNew := []string{}
338         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
339
340         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:[]string{"test1"}}
341         //readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewRnibDbError())
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 TestRemoveE2tInstanceFailureInE2TInstanceManager(t *testing.T) {
351
352         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
353         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
354         mockHttpClientDelete(httpClientMock, data, true)
355
356         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
357         var e2tAddresses []string
358         readerMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
359
360         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:[]string{"test1"}}
361         err := manager.RemoveE2tInstance(e2tInstance1)
362
363         assert.NotNil(t, err)
364         readerMock.AssertExpectations(t)
365         writerMock.AssertExpectations(t)
366         httpClientMock.AssertExpectations(t)
367 }
368
369 func TestRemoveE2tInstanceFailureInE2tInstanceAddRansToInstance(t *testing.T) {
370         manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
371
372         data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
373         mockHttpClientDelete(httpClientMock, data, true)
374
375         writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
376         e2tAddresses := []string{E2TAddress, E2TAddress2, E2TAddress3}
377         readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
378         e2tAddressesNew := []string{E2TAddress2, E2TAddress3}
379         writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
380
381         e2tInstance1 := &entities.E2TInstance{Address: E2TAddress}
382         err := manager.RemoveE2tInstance(e2tInstance1)
383
384         assert.Nil(t, err)
385         readerMock.AssertExpectations(t)
386         writerMock.AssertExpectations(t)
387         httpClientMock.AssertExpectations(t)
388 }
389
390 func mockHttpClientDelete(httpClientMock *mocks.HttpClientMock, data *models.RoutingManagerDeleteRequestModel, isSuccessful bool) {
391
392         marshaled, _ := json.Marshal(data)
393         body := bytes.NewBuffer(marshaled)
394         respBody := ioutil.NopCloser(bytes.NewBufferString(""))
395         var respStatusCode int
396         if isSuccessful {
397                 respStatusCode = http.StatusCreated
398         } else {
399                 respStatusCode = http.StatusBadRequest
400         }
401         httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
402 }