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