6847536ba8f13f975d99d55930c37441775a73ec
[ric-plt/e2mgr.git] / E2Manager / controllers / nodeb_controller_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
18 package controllers
19
20 import (
21         "bytes"
22         "e2mgr/configuration"
23         "e2mgr/e2managererrors"
24         "e2mgr/e2pdus"
25         "e2mgr/logger"
26         "e2mgr/managers"
27         "e2mgr/mocks"
28         "e2mgr/models"
29         "e2mgr/providers/httpmsghandlerprovider"
30         "e2mgr/rmrCgo"
31         "e2mgr/services"
32         "e2mgr/services/rmrsender"
33         "e2mgr/tests"
34         "encoding/json"
35         "fmt"
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/gorilla/mux"
39         "github.com/pkg/errors"
40         "github.com/stretchr/testify/assert"
41         "github.com/stretchr/testify/mock"
42         "io"
43         "io/ioutil"
44         "net/http"
45         "net/http/httptest"
46         "strings"
47         "testing"
48 )
49
50 type controllerGetNodebTestContext struct {
51         ranName              string
52         nodebInfo            *entities.NodebInfo
53         rnibError            error
54         expectedStatusCode   int
55         expectedJsonResponse string
56 }
57
58 type controllerGetNodebIdListTestContext struct {
59         nodebIdList          []*entities.NbIdentity
60         rnibError            error
61         expectedStatusCode   int
62         expectedJsonResponse string
63 }
64
65 func setupControllerTest(t *testing.T) (*NodebController, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock) {
66         log := initLog(t)
67         config := configuration.ParseConfiguration()
68
69         rmrMessengerMock := &mocks.RmrMessengerMock{}
70         readerMock := &mocks.RnibReaderMock{}
71
72         writerMock := &mocks.RnibWriterMock{}
73
74         rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
75         rmrSender := getRmrSender(rmrMessengerMock, log)
76         ranSetupManager := managers.NewRanSetupManager(log, rmrSender, rnibDataService)
77         e2tInstancesManager := &mocks.E2TInstancesManagerMock{}
78         handlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(log, rmrSender, config, rnibDataService, ranSetupManager, e2tInstancesManager)
79         controller := NewNodebController(log, handlerProvider)
80         return controller, readerMock, writerMock, rmrMessengerMock, e2tInstancesManager
81 }
82
83 func TestX2SetupInvalidBody(t *testing.T) {
84
85         controller, _, _, _, _ := setupControllerTest(t)
86
87         header := http.Header{}
88         header.Set("Content-Type", "application/json")
89         httpRequest, _ := http.NewRequest("POST", "http://localhost:3800/v1/nodeb/x2-setup", strings.NewReader("{}{}"))
90         httpRequest.Header = header
91
92         writer := httptest.NewRecorder()
93         controller.X2Setup(writer, httpRequest)
94
95         var errorResponse = parseJsonRequest(t, writer.Body)
96
97         assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
98         assert.Equal(t, e2managererrors.NewInvalidJsonError().Code, errorResponse.Code)
99 }
100
101 func TestX2SetupSuccess(t *testing.T) {
102
103         controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t)
104
105         ranName := "test"
106         nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, AssociatedE2TInstanceAddress:"10.0.2.15:8989"}
107         readerMock.On("GetNodeb", ranName).Return(nb, nil)
108         var nbUpdated = *nb
109         nbUpdated.ConnectionAttempts = 0
110         writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil)
111
112         var nbUpdated2 = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1, AssociatedE2TInstanceAddress:"10.0.2.15:8989"}
113         writerMock.On("UpdateNodebInfo", nbUpdated2).Return(nil)
114
115         payload := e2pdus.PackedX2setupRequest
116         var xAction []byte
117         msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
118
119         rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
120
121         header := http.Header{}
122         header.Set("Content-Type", "application/json")
123         httpRequest := tests.GetHttpRequest()
124         httpRequest.Header = header
125
126         writer := httptest.NewRecorder()
127         controller.X2Setup(writer, httpRequest)
128
129         assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
130 }
131
132
133 func TestEndcSetupSuccess(t *testing.T) {
134
135         controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t)
136
137         ranName := "test"
138         nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, AssociatedE2TInstanceAddress:"10.0.2.15:8989"}
139         readerMock.On("GetNodeb", ranName).Return(nb, nil)
140         var nbUpdated = *nb
141         nbUpdated.ConnectionAttempts = 0
142         writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil)
143
144         var nbUpdated2 = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1, AssociatedE2TInstanceAddress:"10.0.2.15:8989"}
145         writerMock.On("UpdateNodebInfo", nbUpdated2).Return(nil)
146
147         payload := e2pdus.PackedEndcX2setupRequest
148         var xAction[]byte
149         msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
150
151         rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
152
153         header := http.Header{}
154         header.Set("Content-Type", "application/json")
155         httpRequest := tests.GetHttpRequest()
156         httpRequest.Header = header
157
158         writer := httptest.NewRecorder()
159         controller.EndcSetup(writer, httpRequest)
160
161         assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
162 }
163
164 func TestShutdownHandlerRnibError(t *testing.T) {
165         controller, readerMock, _, _, _ := setupControllerTest(t)
166
167         rnibErr := &common.ResourceNotFoundError{}
168         var nbIdentityList []*entities.NbIdentity
169         readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibErr)
170
171         writer := httptest.NewRecorder()
172
173         controller.Shutdown(writer, tests.GetHttpRequest())
174
175         var errorResponse = parseJsonRequest(t, writer.Body)
176
177         assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
178         assert.Equal(t, errorResponse.Code, e2managererrors.NewRnibDbError().Code)
179 }
180
181 func controllerGetNodebTestExecuter(t *testing.T, context *controllerGetNodebTestContext) {
182         controller, readerMock, _, _, _ := setupControllerTest(t)
183         writer := httptest.NewRecorder()
184         readerMock.On("GetNodeb", context.ranName).Return(context.nodebInfo, context.rnibError)
185         req, _ := http.NewRequest("GET", "/nodeb", nil)
186         req = mux.SetURLVars(req, map[string]string{"ranName": context.ranName})
187         controller.GetNodeb(writer, req)
188         assert.Equal(t, context.expectedStatusCode, writer.Result().StatusCode)
189         bodyBytes, _ := ioutil.ReadAll(writer.Body)
190         assert.Equal(t, context.expectedJsonResponse, string(bodyBytes))
191 }
192
193 func controllerGetNodebIdListTestExecuter(t *testing.T, context *controllerGetNodebIdListTestContext) {
194         controller, readerMock, _, _, _ := setupControllerTest(t)
195         writer := httptest.NewRecorder()
196         readerMock.On("GetListNodebIds").Return(context.nodebIdList, context.rnibError)
197         req, _ := http.NewRequest("GET", "/nodeb/ids", nil)
198         controller.GetNodebIdList(writer, req)
199         assert.Equal(t, context.expectedStatusCode, writer.Result().StatusCode)
200         bodyBytes, _ := ioutil.ReadAll(writer.Body)
201         assert.Equal(t, context.expectedJsonResponse, string(bodyBytes))
202 }
203
204 func TestControllerGetNodebSuccess(t *testing.T) {
205         ranName := "test"
206         var rnibError error
207         context := controllerGetNodebTestContext{
208                 ranName:              ranName,
209                 nodebInfo:            &entities.NodebInfo{RanName: ranName, Ip: "10.0.2.15", Port: 1234},
210                 rnibError:            rnibError,
211                 expectedStatusCode:   http.StatusOK,
212                 expectedJsonResponse: fmt.Sprintf("{\"ranName\":\"%s\",\"ip\":\"10.0.2.15\",\"port\":1234}", ranName),
213         }
214
215         controllerGetNodebTestExecuter(t, &context)
216 }
217
218 func TestControllerGetNodebNotFound(t *testing.T) {
219
220         ranName := "test"
221         var nodebInfo *entities.NodebInfo
222         context := controllerGetNodebTestContext{
223                 ranName:              ranName,
224                 nodebInfo:            nodebInfo,
225                 rnibError:            common.NewResourceNotFoundError("#reader.GetNodeb - Not found Error"),
226                 expectedStatusCode:   http.StatusNotFound,
227                 expectedJsonResponse: "{\"errorCode\":404,\"errorMessage\":\"Resource not found\"}",
228         }
229
230         controllerGetNodebTestExecuter(t, &context)
231 }
232
233 func TestControllerGetNodebInternal(t *testing.T) {
234         ranName := "test"
235         var nodebInfo *entities.NodebInfo
236         context := controllerGetNodebTestContext{
237                 ranName:              ranName,
238                 nodebInfo:            nodebInfo,
239                 rnibError:            common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
240                 expectedStatusCode:   http.StatusInternalServerError,
241                 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
242         }
243
244         controllerGetNodebTestExecuter(t, &context)
245 }
246
247 func TestControllerGetNodebIdListSuccess(t *testing.T) {
248         var rnibError error
249         nodebIdList := []*entities.NbIdentity{
250                 {InventoryName: "test1", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId1", NbId: "nbId1"}},
251                 {InventoryName: "test2", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId2", NbId: "nbId2"}},
252         }
253
254         context := controllerGetNodebIdListTestContext{
255                 nodebIdList:          nodebIdList,
256                 rnibError:            rnibError,
257                 expectedStatusCode:   http.StatusOK,
258                 expectedJsonResponse: "[{\"inventoryName\":\"test1\",\"globalNbId\":{\"plmnId\":\"plmnId1\",\"nbId\":\"nbId1\"}},{\"inventoryName\":\"test2\",\"globalNbId\":{\"plmnId\":\"plmnId2\",\"nbId\":\"nbId2\"}}]",
259         }
260
261         controllerGetNodebIdListTestExecuter(t, &context)
262 }
263
264 func TestControllerGetNodebIdListEmptySuccess(t *testing.T) {
265         var rnibError error
266         nodebIdList := []*entities.NbIdentity{}
267
268         context := controllerGetNodebIdListTestContext{
269                 nodebIdList:          nodebIdList,
270                 rnibError:            rnibError,
271                 expectedStatusCode:   http.StatusOK,
272                 expectedJsonResponse: "[]",
273         }
274
275         controllerGetNodebIdListTestExecuter(t, &context)
276 }
277
278 func TestControllerGetNodebIdListInternal(t *testing.T) {
279         var nodebIdList []*entities.NbIdentity
280         context := controllerGetNodebIdListTestContext{
281                 nodebIdList:          nodebIdList,
282                 rnibError:            common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
283                 expectedStatusCode:   http.StatusInternalServerError,
284                 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
285         }
286
287         controllerGetNodebIdListTestExecuter(t, &context)
288 }
289
290 func TestHeaderValidationFailed(t *testing.T) {
291         controller, _, _, _, _ := setupControllerTest(t)
292
293         writer := httptest.NewRecorder()
294
295         header := &http.Header{}
296
297         controller.handleRequest(writer, header, httpmsghandlerprovider.ShutdownRequest, nil, true)
298
299         var errorResponse = parseJsonRequest(t, writer.Body)
300         err := e2managererrors.NewHeaderValidationError()
301
302         assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
303         assert.Equal(t, errorResponse.Code, err.Code)
304         assert.Equal(t, errorResponse.Message, err.Message)
305 }
306
307 func TestShutdownStatusNoContent(t *testing.T) {
308         controller, readerMock, _, _, _ := setupControllerTest(t)
309
310         var rnibError error
311         nbIdentityList := []*entities.NbIdentity{}
312         readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibError)
313
314         writer := httptest.NewRecorder()
315         controller.Shutdown(writer, tests.GetHttpRequest())
316
317         assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
318 }
319
320 func TestHandleInternalError(t *testing.T) {
321         controller, _, _, _, _ := setupControllerTest(t)
322
323         writer := httptest.NewRecorder()
324         err := e2managererrors.NewInternalError()
325
326         controller.handleErrorResponse(err, writer)
327         var errorResponse = parseJsonRequest(t, writer.Body)
328
329         assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
330         assert.Equal(t, errorResponse.Code, err.Code)
331         assert.Equal(t, errorResponse.Message, err.Message)
332 }
333
334 func TestHandleCommandAlreadyInProgressError(t *testing.T) {
335         controller, _, _, _, _ := setupControllerTest(t)
336         writer := httptest.NewRecorder()
337         err := e2managererrors.NewCommandAlreadyInProgressError()
338
339         controller.handleErrorResponse(err, writer)
340         var errorResponse = parseJsonRequest(t, writer.Body)
341
342         assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
343         assert.Equal(t, errorResponse.Code, err.Code)
344         assert.Equal(t, errorResponse.Message, err.Message)
345 }
346
347 func TestHandleE2TInstanceAbsenceError(t *testing.T) {
348         controller, _, _, _, _ := setupControllerTest(t)
349
350         writer := httptest.NewRecorder()
351         err := e2managererrors.NewE2TInstanceAbsenceError()
352
353         controller.handleErrorResponse(err, writer)
354         var errorResponse = parseJsonRequest(t, writer.Body)
355
356         assert.Equal(t, http.StatusServiceUnavailable, writer.Result().StatusCode)
357         assert.Equal(t, errorResponse.Code, err.Code)
358         assert.Equal(t, errorResponse.Message, err.Message)
359 }
360
361 func TestValidateHeaders(t *testing.T) {
362         controller, _, _, _, _ := setupControllerTest(t)
363
364         header := http.Header{}
365         header.Set("Content-Type", "application/json")
366         result := controller.validateRequestHeader(&header)
367
368         assert.Nil(t, result)
369 }
370
371 func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse {
372
373         var errorResponse models.ErrorResponse
374         body, err := ioutil.ReadAll(r)
375         if err != nil {
376                 t.Errorf("Error cannot deserialize json request")
377         }
378         json.Unmarshal(body, &errorResponse)
379
380         return errorResponse
381 }
382
383 func initLog(t *testing.T) *logger.Logger {
384         log, err := logger.InitLogger(logger.InfoLevel)
385         if err != nil {
386                 t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err)
387         }
388         return log
389 }
390
391 func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) {
392         controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t)
393
394         ranName := "test1"
395         payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40}
396         var xAction []byte
397         msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
398         rmrMessengerMock.On("SendMsg", msg, mock.Anything).Return(msg, nil)
399
400         writer := httptest.NewRecorder()
401
402         var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
403         readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
404
405         data4Req := map[string]interface{}{"cause": "protocol:transfer-syntax-error"}
406         b := new(bytes.Buffer)
407         _ = json.NewEncoder(b).Encode(data4Req)
408         req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
409         req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
410
411         controller.X2Reset(writer, req)
412         assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
413
414 }
415
416 func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) {
417         controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t)
418
419         ranName := "test1"
420         // o&m intervention
421         payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64}
422         var xAction []byte
423         msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
424         rmrMessengerMock.On("SendMsg", msg).Return(msg, nil)
425
426         writer := httptest.NewRecorder()
427
428         var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
429         readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
430
431         // no body
432         b := new(bytes.Buffer)
433         req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
434         req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
435
436         controller.X2Reset(writer, req)
437         assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
438
439 }
440
441 func TestX2ResetHandleFailureInvalidBody(t *testing.T) {
442         controller, _, _, _ , _:= setupControllerTest(t)
443
444         ranName := "test1"
445
446         writer := httptest.NewRecorder()
447
448         // Invalid json: attribute name without quotes (should be "cause":).
449         b := strings.NewReader("{cause:\"protocol:transfer-syntax-error\"")
450         req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
451         req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
452
453         controller.X2Reset(writer, req)
454         assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
455
456 }
457
458 func TestHandleErrorResponse(t *testing.T) {
459         controller, _, _, _ , _:= setupControllerTest(t)
460
461         writer := httptest.NewRecorder()
462         controller.handleErrorResponse(e2managererrors.NewRnibDbError(), writer)
463         assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
464
465         writer = httptest.NewRecorder()
466         controller.handleErrorResponse(e2managererrors.NewCommandAlreadyInProgressError(), writer)
467         assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
468
469         writer = httptest.NewRecorder()
470         controller.handleErrorResponse(e2managererrors.NewHeaderValidationError(), writer)
471         assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
472
473         writer = httptest.NewRecorder()
474         controller.handleErrorResponse(e2managererrors.NewWrongStateError("", ""), writer)
475         assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
476
477         writer = httptest.NewRecorder()
478         controller.handleErrorResponse(e2managererrors.NewRequestValidationError(), writer)
479         assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
480
481         writer = httptest.NewRecorder()
482         controller.handleErrorResponse(e2managererrors.NewRmrError(), writer)
483         assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
484
485         writer = httptest.NewRecorder()
486         controller.handleErrorResponse(e2managererrors.NewResourceNotFoundError(), writer)
487         assert.Equal(t, http.StatusNotFound, writer.Result().StatusCode)
488
489         writer = httptest.NewRecorder()
490         controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer)
491         assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
492 }
493
494 func getRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender {
495         rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock)
496         rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger)
497         return rmrsender.NewRmrSender(log, rmrMessenger)
498 }