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