2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
23 "e2mgr/e2managererrors"
29 "e2mgr/providers/httpmsghandlerprovider"
32 "e2mgr/services/rmrsender"
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"
50 type controllerGetNodebTestContext struct {
52 nodebInfo *entities.NodebInfo
54 expectedStatusCode int
55 expectedJsonResponse string
58 type controllerGetNodebIdListTestContext struct {
59 nodebIdList []*entities.NbIdentity
61 expectedStatusCode int
62 expectedJsonResponse string
65 func setupControllerTest(t *testing.T) (*NodebController, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock) {
67 config := configuration.ParseConfiguration()
69 rmrMessengerMock := &mocks.RmrMessengerMock{}
70 readerMock := &mocks.RnibReaderMock{}
72 writerMock := &mocks.RnibWriterMock{}
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
83 func TestX2SetupInvalidBody(t *testing.T) {
85 controller, _, _, _, _ := setupControllerTest(t)
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
92 writer := httptest.NewRecorder()
93 controller.X2Setup(writer, httpRequest)
95 var errorResponse = parseJsonRequest(t, writer.Body)
97 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
98 assert.Equal(t, e2managererrors.NewInvalidJsonError().Code, errorResponse.Code)
101 func TestX2SetupSuccess(t *testing.T) {
103 controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t)
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)
109 nbUpdated.ConnectionAttempts = 0
110 writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil)
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)
115 payload := e2pdus.PackedX2setupRequest
117 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
119 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
121 header := http.Header{}
122 header.Set("Content-Type", "application/json")
123 httpRequest := tests.GetHttpRequest()
124 httpRequest.Header = header
126 writer := httptest.NewRecorder()
127 controller.X2Setup(writer, httpRequest)
129 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
133 func TestEndcSetupSuccess(t *testing.T) {
135 controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t)
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)
141 nbUpdated.ConnectionAttempts = 0
142 writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil)
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)
147 payload := e2pdus.PackedEndcX2setupRequest
149 msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
151 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
153 header := http.Header{}
154 header.Set("Content-Type", "application/json")
155 httpRequest := tests.GetHttpRequest()
156 httpRequest.Header = header
158 writer := httptest.NewRecorder()
159 controller.EndcSetup(writer, httpRequest)
161 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
164 func TestShutdownHandlerRnibError(t *testing.T) {
165 controller, readerMock, _, _, _ := setupControllerTest(t)
167 rnibErr := &common.ResourceNotFoundError{}
168 var nbIdentityList []*entities.NbIdentity
169 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibErr)
171 writer := httptest.NewRecorder()
173 controller.Shutdown(writer, tests.GetHttpRequest())
175 var errorResponse = parseJsonRequest(t, writer.Body)
177 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
178 assert.Equal(t, errorResponse.Code, e2managererrors.NewRnibDbError().Code)
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))
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))
204 func TestControllerGetNodebSuccess(t *testing.T) {
207 context := controllerGetNodebTestContext{
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),
215 controllerGetNodebTestExecuter(t, &context)
218 func TestControllerGetNodebNotFound(t *testing.T) {
221 var nodebInfo *entities.NodebInfo
222 context := controllerGetNodebTestContext{
224 nodebInfo: nodebInfo,
225 rnibError: common.NewResourceNotFoundError("#reader.GetNodeb - Not found Error"),
226 expectedStatusCode: http.StatusNotFound,
227 expectedJsonResponse: "{\"errorCode\":404,\"errorMessage\":\"Resource not found\"}",
230 controllerGetNodebTestExecuter(t, &context)
233 func TestControllerGetNodebInternal(t *testing.T) {
235 var nodebInfo *entities.NodebInfo
236 context := controllerGetNodebTestContext{
238 nodebInfo: nodebInfo,
239 rnibError: common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
240 expectedStatusCode: http.StatusInternalServerError,
241 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
244 controllerGetNodebTestExecuter(t, &context)
247 func TestControllerGetNodebIdListSuccess(t *testing.T) {
249 nodebIdList := []*entities.NbIdentity{
250 {InventoryName: "test1", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId1", NbId: "nbId1"}},
251 {InventoryName: "test2", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId2", NbId: "nbId2"}},
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\"}}]",
261 controllerGetNodebIdListTestExecuter(t, &context)
264 func TestControllerGetNodebIdListEmptySuccess(t *testing.T) {
266 nodebIdList := []*entities.NbIdentity{}
268 context := controllerGetNodebIdListTestContext{
269 nodebIdList: nodebIdList,
270 rnibError: rnibError,
271 expectedStatusCode: http.StatusOK,
272 expectedJsonResponse: "[]",
275 controllerGetNodebIdListTestExecuter(t, &context)
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\"}",
287 controllerGetNodebIdListTestExecuter(t, &context)
290 func TestHeaderValidationFailed(t *testing.T) {
291 controller, _, _, _, _ := setupControllerTest(t)
293 writer := httptest.NewRecorder()
295 header := &http.Header{}
297 controller.handleRequest(writer, header, httpmsghandlerprovider.ShutdownRequest, nil, true)
299 var errorResponse = parseJsonRequest(t, writer.Body)
300 err := e2managererrors.NewHeaderValidationError()
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)
307 func TestShutdownStatusNoContent(t *testing.T) {
308 controller, readerMock, _, _, _ := setupControllerTest(t)
311 nbIdentityList := []*entities.NbIdentity{}
312 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibError)
314 writer := httptest.NewRecorder()
315 controller.Shutdown(writer, tests.GetHttpRequest())
317 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
320 func TestHandleInternalError(t *testing.T) {
321 controller, _, _, _, _ := setupControllerTest(t)
323 writer := httptest.NewRecorder()
324 err := e2managererrors.NewInternalError()
326 controller.handleErrorResponse(err, writer)
327 var errorResponse = parseJsonRequest(t, writer.Body)
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)
334 func TestHandleCommandAlreadyInProgressError(t *testing.T) {
335 controller, _, _, _, _ := setupControllerTest(t)
336 writer := httptest.NewRecorder()
337 err := e2managererrors.NewCommandAlreadyInProgressError()
339 controller.handleErrorResponse(err, writer)
340 var errorResponse = parseJsonRequest(t, writer.Body)
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)
347 func TestHandleE2TInstanceAbsenceError(t *testing.T) {
348 controller, _, _, _, _ := setupControllerTest(t)
350 writer := httptest.NewRecorder()
351 err := e2managererrors.NewE2TInstanceAbsenceError()
353 controller.handleErrorResponse(err, writer)
354 var errorResponse = parseJsonRequest(t, writer.Body)
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)
361 func TestValidateHeaders(t *testing.T) {
362 controller, _, _, _, _ := setupControllerTest(t)
364 header := http.Header{}
365 header.Set("Content-Type", "application/json")
366 result := controller.validateRequestHeader(&header)
368 assert.Nil(t, result)
371 func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse {
373 var errorResponse models.ErrorResponse
374 body, err := ioutil.ReadAll(r)
376 t.Errorf("Error cannot deserialize json request")
378 json.Unmarshal(body, &errorResponse)
383 func initLog(t *testing.T) *logger.Logger {
384 log, err := logger.InitLogger(logger.InfoLevel)
386 t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err)
391 func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) {
392 controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t)
395 payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40}
397 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
398 rmrMessengerMock.On("SendMsg", msg, mock.Anything).Return(msg, nil)
400 writer := httptest.NewRecorder()
402 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
403 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
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})
411 controller.X2Reset(writer, req)
412 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
416 func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) {
417 controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t)
421 payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64}
423 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
424 rmrMessengerMock.On("SendMsg", msg).Return(msg, nil)
426 writer := httptest.NewRecorder()
428 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
429 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
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})
436 controller.X2Reset(writer, req)
437 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
441 func TestX2ResetHandleFailureInvalidBody(t *testing.T) {
442 controller, _, _, _ , _:= setupControllerTest(t)
446 writer := httptest.NewRecorder()
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})
453 controller.X2Reset(writer, req)
454 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
458 func TestHandleErrorResponse(t *testing.T) {
459 controller, _, _, _ , _:= setupControllerTest(t)
461 writer := httptest.NewRecorder()
462 controller.handleErrorResponse(e2managererrors.NewRnibDbError(), writer)
463 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
465 writer = httptest.NewRecorder()
466 controller.handleErrorResponse(e2managererrors.NewCommandAlreadyInProgressError(), writer)
467 assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
469 writer = httptest.NewRecorder()
470 controller.handleErrorResponse(e2managererrors.NewHeaderValidationError(), writer)
471 assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
473 writer = httptest.NewRecorder()
474 controller.handleErrorResponse(e2managererrors.NewWrongStateError("", ""), writer)
475 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
477 writer = httptest.NewRecorder()
478 controller.handleErrorResponse(e2managererrors.NewRequestValidationError(), writer)
479 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
481 writer = httptest.NewRecorder()
482 controller.handleErrorResponse(e2managererrors.NewRmrError(), writer)
483 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
485 writer = httptest.NewRecorder()
486 controller.handleErrorResponse(e2managererrors.NewResourceNotFoundError(), writer)
487 assert.Equal(t, http.StatusNotFound, writer.Result().StatusCode)
489 writer = httptest.NewRecorder()
490 controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer)
491 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
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)