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.
17 // This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 // platform project (RICP).
26 "e2mgr/e2managererrors"
32 "e2mgr/providers/httpmsghandlerprovider"
36 "e2mgr/services/rmrsender"
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"
55 type controllerGetNodebTestContext struct {
57 nodebInfo *entities.NodebInfo
59 expectedStatusCode int
60 expectedJsonResponse string
63 type controllerGetNodebIdListTestContext struct {
64 nodebIdList []*entities.NbIdentity
66 expectedStatusCode int
67 expectedJsonResponse string
70 func setupControllerTest(t *testing.T) (*NodebController, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock) {
72 config := configuration.ParseConfiguration()
74 rmrMessengerMock := &mocks.RmrMessengerMock{}
75 readerMock := &mocks.RnibReaderMock{}
76 readerProvider := func() reader.RNibReader {
79 writerMock := &mocks.RnibWriterMock{}
80 writerProvider := func() rNibWriter.RNibWriter {
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
91 func TestX2SetupInvalidBody(t *testing.T) {
93 controller, _, _, _ := setupControllerTest(t)
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
100 writer := httptest.NewRecorder()
101 controller.X2Setup(writer, httpRequest)
103 var errorResponse = parseJsonRequest(t, writer.Body)
105 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
106 assert.Equal(t, e2managererrors.NewInvalidJsonError().Code, errorResponse.Code)
109 func TestX2SetupSuccess(t *testing.T) {
111 controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t)
114 nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
115 readerMock.On("GetNodeb", ranName).Return(nb, nil)
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)
120 payload := e2pdus.PackedX2setupRequest
121 xaction := []byte(ranName)
122 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction)
124 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
126 header := http.Header{}
127 header.Set("Content-Type", "application/json")
128 httpRequest := tests.GetHttpRequest()
129 httpRequest.Header = header
131 writer := httptest.NewRecorder()
132 controller.X2Setup(writer, httpRequest)
134 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
137 func TestEndcSetupSuccess(t *testing.T) {
139 controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t)
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)
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)
148 payload := e2pdus.PackedEndcX2setupRequest
149 xaction := []byte(ranName)
150 msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction)
152 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
154 header := http.Header{}
155 header.Set("Content-Type", "application/json")
156 httpRequest := tests.GetHttpRequest()
157 httpRequest.Header = header
159 writer := httptest.NewRecorder()
160 controller.EndcSetup(writer, httpRequest)
162 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
165 func TestShutdownHandlerRnibError(t *testing.T) {
166 controller, readerMock, _, _ := setupControllerTest(t)
168 rnibErr := &common.ResourceNotFoundError{}
169 var nbIdentityList []*entities.NbIdentity
170 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibErr)
172 writer := httptest.NewRecorder()
174 controller.Shutdown(writer, tests.GetHttpRequest())
176 var errorResponse = parseJsonRequest(t, writer.Body)
178 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
179 assert.Equal(t, errorResponse.Code, e2managererrors.NewRnibDbError().Code)
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))
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))
205 func TestControllerGetNodebSuccess(t *testing.T) {
208 context := controllerGetNodebTestContext{
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),
216 controllerGetNodebTestExecuter(t, &context)
219 func TestControllerGetNodebNotFound(t *testing.T) {
222 var nodebInfo *entities.NodebInfo
223 context := controllerGetNodebTestContext{
225 nodebInfo: nodebInfo,
226 rnibError: common.NewResourceNotFoundError("#reader.GetNodeb - Not found Error"),
227 expectedStatusCode: http.StatusNotFound,
228 expectedJsonResponse: "{\"errorCode\":404,\"errorMessage\":\"Resource not found\"}",
231 controllerGetNodebTestExecuter(t, &context)
234 func TestControllerGetNodebInternal(t *testing.T) {
236 var nodebInfo *entities.NodebInfo
237 context := controllerGetNodebTestContext{
239 nodebInfo: nodebInfo,
240 rnibError: common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
241 expectedStatusCode: http.StatusInternalServerError,
242 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
245 controllerGetNodebTestExecuter(t, &context)
248 func TestControllerGetNodebIdListSuccess(t *testing.T) {
250 nodebIdList := []*entities.NbIdentity{
251 {InventoryName: "test1", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId1", NbId: "nbId1"}},
252 {InventoryName: "test2", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId2", NbId: "nbId2"}},
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\"}}]",
262 controllerGetNodebIdListTestExecuter(t, &context)
265 func TestControllerGetNodebIdListEmptySuccess(t *testing.T) {
267 nodebIdList := []*entities.NbIdentity{}
269 context := controllerGetNodebIdListTestContext{
270 nodebIdList: nodebIdList,
271 rnibError: rnibError,
272 expectedStatusCode: http.StatusOK,
273 expectedJsonResponse: "[]",
276 controllerGetNodebIdListTestExecuter(t, &context)
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\"}",
288 controllerGetNodebIdListTestExecuter(t, &context)
291 func TestHeaderValidationFailed(t *testing.T) {
292 controller, _, _, _ := setupControllerTest(t)
294 writer := httptest.NewRecorder()
296 header := &http.Header{}
298 controller.handleRequest(writer, header, httpmsghandlerprovider.ShutdownRequest, nil, true)
300 var errorResponse = parseJsonRequest(t, writer.Body)
301 err := e2managererrors.NewHeaderValidationError()
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)
308 func TestShutdownStatusNoContent(t *testing.T) {
309 controller, readerMock, _, _ := setupControllerTest(t)
312 nbIdentityList := []*entities.NbIdentity{}
313 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibError)
315 writer := httptest.NewRecorder()
316 controller.Shutdown(writer, tests.GetHttpRequest())
318 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
321 func TestHandleInternalError(t *testing.T) {
322 controller, _, _, _ := setupControllerTest(t)
324 writer := httptest.NewRecorder()
325 err := e2managererrors.NewInternalError()
327 controller.handleErrorResponse(err, writer)
328 var errorResponse = parseJsonRequest(t, writer.Body)
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)
335 func TestHandleCommandAlreadyInProgressError(t *testing.T) {
336 controller, _, _, _ := setupControllerTest(t)
337 writer := httptest.NewRecorder()
338 err := e2managererrors.NewCommandAlreadyInProgressError()
340 controller.handleErrorResponse(err, writer)
341 var errorResponse = parseJsonRequest(t, writer.Body)
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)
348 func TestValidateHeaders(t *testing.T) {
349 controller, _, _, _ := setupControllerTest(t)
351 header := http.Header{}
352 header.Set("Content-Type", "application/json")
353 result := controller.validateRequestHeader(&header)
355 assert.Nil(t, result)
358 func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse {
360 var errorResponse models.ErrorResponse
361 body, err := ioutil.ReadAll(r)
363 t.Errorf("Error cannot deserialize json request")
365 json.Unmarshal(body, &errorResponse)
370 func initLog(t *testing.T) *logger.Logger {
371 log, err := logger.InitLogger(logger.InfoLevel)
373 t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err)
378 func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) {
379 controller, readerMock, _, rmrMessengerMock := setupControllerTest(t)
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)
387 writer := httptest.NewRecorder()
389 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
390 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
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})
398 controller.X2Reset(writer, req)
399 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
403 func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) {
404 controller, readerMock, _, rmrMessengerMock := setupControllerTest(t)
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)
413 writer := httptest.NewRecorder()
415 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
416 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
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})
423 controller.X2Reset(writer, req)
424 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
428 func TestX2ResetHandleFailureInvalidBody(t *testing.T) {
429 controller, _, _, _ := setupControllerTest(t)
433 writer := httptest.NewRecorder()
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})
440 controller.X2Reset(writer, req)
441 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
445 func TestHandleErrorResponse(t *testing.T) {
446 controller, _, _, _ := setupControllerTest(t)
448 writer := httptest.NewRecorder()
449 controller.handleErrorResponse(e2managererrors.NewRnibDbError(), writer)
450 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
452 writer = httptest.NewRecorder()
453 controller.handleErrorResponse(e2managererrors.NewCommandAlreadyInProgressError(), writer)
454 assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
456 writer = httptest.NewRecorder()
457 controller.handleErrorResponse(e2managererrors.NewHeaderValidationError(), writer)
458 assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
460 writer = httptest.NewRecorder()
461 controller.handleErrorResponse(e2managererrors.NewWrongStateError("", ""), writer)
462 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
464 writer = httptest.NewRecorder()
465 controller.handleErrorResponse(e2managererrors.NewRequestValidationError(), writer)
466 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
468 writer = httptest.NewRecorder()
469 controller.handleErrorResponse(e2managererrors.NewRmrError(), writer)
470 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
472 writer = httptest.NewRecorder()
473 controller.handleErrorResponse(e2managererrors.NewResourceNotFoundError(), writer)
474 assert.Equal(t, http.StatusNotFound, writer.Result().StatusCode)
476 writer = httptest.NewRecorder()
477 controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer)
478 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
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)