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