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