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) {
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 handlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(log, rmrSender, config, rnibDataService, ranSetupManager)
78 controller := NewNodebController(log, handlerProvider)
79 return controller, readerMock, writerMock, rmrMessengerMock
82 func TestX2SetupInvalidBody(t *testing.T) {
84 controller, _, _, _ := setupControllerTest(t)
86 header := http.Header{}
87 header.Set("Content-Type", "application/json")
88 httpRequest, _ := http.NewRequest("POST", "http://localhost:3800/v1/nodeb/x2-setup", strings.NewReader("{}{}"))
89 httpRequest.Header = header
91 writer := httptest.NewRecorder()
92 controller.X2Setup(writer, httpRequest)
94 var errorResponse = parseJsonRequest(t, writer.Body)
96 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
97 assert.Equal(t, e2managererrors.NewInvalidJsonError().Code, errorResponse.Code)
100 func TestX2SetupSuccess(t *testing.T) {
102 controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t)
105 nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
106 readerMock.On("GetNodeb", ranName).Return(nb, nil)
108 var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1}
109 writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil)
111 payload := e2pdus.PackedX2setupRequest
113 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
115 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
117 header := http.Header{}
118 header.Set("Content-Type", "application/json")
119 httpRequest := tests.GetHttpRequest()
120 httpRequest.Header = header
122 writer := httptest.NewRecorder()
123 controller.X2Setup(writer, httpRequest)
125 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
128 func TestEndcSetupSuccess(t *testing.T) {
130 controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t)
133 nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST}
134 readerMock.On("GetNodeb", ranName).Return(nb, nil)
136 var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1}
137 writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil)
139 payload := e2pdus.PackedEndcX2setupRequest
141 msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction)
143 rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil)
145 header := http.Header{}
146 header.Set("Content-Type", "application/json")
147 httpRequest := tests.GetHttpRequest()
148 httpRequest.Header = header
150 writer := httptest.NewRecorder()
151 controller.EndcSetup(writer, httpRequest)
153 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
156 func TestShutdownHandlerRnibError(t *testing.T) {
157 controller, readerMock, _, _ := setupControllerTest(t)
159 rnibErr := &common.ResourceNotFoundError{}
160 var nbIdentityList []*entities.NbIdentity
161 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibErr)
163 writer := httptest.NewRecorder()
165 controller.Shutdown(writer, tests.GetHttpRequest())
167 var errorResponse = parseJsonRequest(t, writer.Body)
169 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
170 assert.Equal(t, errorResponse.Code, e2managererrors.NewRnibDbError().Code)
173 func controllerGetNodebTestExecuter(t *testing.T, context *controllerGetNodebTestContext) {
174 controller, readerMock, _, _ := setupControllerTest(t)
175 writer := httptest.NewRecorder()
176 readerMock.On("GetNodeb", context.ranName).Return(context.nodebInfo, context.rnibError)
177 req, _ := http.NewRequest("GET", "/nodeb", nil)
178 req = mux.SetURLVars(req, map[string]string{"ranName": context.ranName})
179 controller.GetNodeb(writer, req)
180 assert.Equal(t, context.expectedStatusCode, writer.Result().StatusCode)
181 bodyBytes, _ := ioutil.ReadAll(writer.Body)
182 assert.Equal(t, context.expectedJsonResponse, string(bodyBytes))
185 func controllerGetNodebIdListTestExecuter(t *testing.T, context *controllerGetNodebIdListTestContext) {
186 controller, readerMock, _, _ := setupControllerTest(t)
187 writer := httptest.NewRecorder()
188 readerMock.On("GetListNodebIds").Return(context.nodebIdList, context.rnibError)
189 req, _ := http.NewRequest("GET", "/nodeb/ids", nil)
190 controller.GetNodebIdList(writer, req)
191 assert.Equal(t, context.expectedStatusCode, writer.Result().StatusCode)
192 bodyBytes, _ := ioutil.ReadAll(writer.Body)
193 assert.Equal(t, context.expectedJsonResponse, string(bodyBytes))
196 func TestControllerGetNodebSuccess(t *testing.T) {
199 context := controllerGetNodebTestContext{
201 nodebInfo: &entities.NodebInfo{RanName: ranName, Ip: "10.0.2.15", Port: 1234},
202 rnibError: rnibError,
203 expectedStatusCode: http.StatusOK,
204 expectedJsonResponse: fmt.Sprintf("{\"ranName\":\"%s\",\"ip\":\"10.0.2.15\",\"port\":1234}", ranName),
207 controllerGetNodebTestExecuter(t, &context)
210 func TestControllerGetNodebNotFound(t *testing.T) {
213 var nodebInfo *entities.NodebInfo
214 context := controllerGetNodebTestContext{
216 nodebInfo: nodebInfo,
217 rnibError: common.NewResourceNotFoundError("#reader.GetNodeb - Not found Error"),
218 expectedStatusCode: http.StatusNotFound,
219 expectedJsonResponse: "{\"errorCode\":404,\"errorMessage\":\"Resource not found\"}",
222 controllerGetNodebTestExecuter(t, &context)
225 func TestControllerGetNodebInternal(t *testing.T) {
227 var nodebInfo *entities.NodebInfo
228 context := controllerGetNodebTestContext{
230 nodebInfo: nodebInfo,
231 rnibError: common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
232 expectedStatusCode: http.StatusInternalServerError,
233 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
236 controllerGetNodebTestExecuter(t, &context)
239 func TestControllerGetNodebIdListSuccess(t *testing.T) {
241 nodebIdList := []*entities.NbIdentity{
242 {InventoryName: "test1", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId1", NbId: "nbId1"}},
243 {InventoryName: "test2", GlobalNbId: &entities.GlobalNbId{PlmnId: "plmnId2", NbId: "nbId2"}},
246 context := controllerGetNodebIdListTestContext{
247 nodebIdList: nodebIdList,
248 rnibError: rnibError,
249 expectedStatusCode: http.StatusOK,
250 expectedJsonResponse: "[{\"inventoryName\":\"test1\",\"globalNbId\":{\"plmnId\":\"plmnId1\",\"nbId\":\"nbId1\"}},{\"inventoryName\":\"test2\",\"globalNbId\":{\"plmnId\":\"plmnId2\",\"nbId\":\"nbId2\"}}]",
253 controllerGetNodebIdListTestExecuter(t, &context)
256 func TestControllerGetNodebIdListEmptySuccess(t *testing.T) {
258 nodebIdList := []*entities.NbIdentity{}
260 context := controllerGetNodebIdListTestContext{
261 nodebIdList: nodebIdList,
262 rnibError: rnibError,
263 expectedStatusCode: http.StatusOK,
264 expectedJsonResponse: "[]",
267 controllerGetNodebIdListTestExecuter(t, &context)
270 func TestControllerGetNodebIdListInternal(t *testing.T) {
271 var nodebIdList []*entities.NbIdentity
272 context := controllerGetNodebIdListTestContext{
273 nodebIdList: nodebIdList,
274 rnibError: common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")),
275 expectedStatusCode: http.StatusInternalServerError,
276 expectedJsonResponse: "{\"errorCode\":500,\"errorMessage\":\"RNIB error\"}",
279 controllerGetNodebIdListTestExecuter(t, &context)
282 func TestHeaderValidationFailed(t *testing.T) {
283 controller, _, _, _ := setupControllerTest(t)
285 writer := httptest.NewRecorder()
287 header := &http.Header{}
289 controller.handleRequest(writer, header, httpmsghandlerprovider.ShutdownRequest, nil, true)
291 var errorResponse = parseJsonRequest(t, writer.Body)
292 err := e2managererrors.NewHeaderValidationError()
294 assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
295 assert.Equal(t, errorResponse.Code, err.Code)
296 assert.Equal(t, errorResponse.Message, err.Message)
299 func TestShutdownStatusNoContent(t *testing.T) {
300 controller, readerMock, _, _ := setupControllerTest(t)
303 nbIdentityList := []*entities.NbIdentity{}
304 readerMock.On("GetListNodebIds").Return(nbIdentityList, rnibError)
306 writer := httptest.NewRecorder()
307 controller.Shutdown(writer, tests.GetHttpRequest())
309 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
312 func TestHandleInternalError(t *testing.T) {
313 controller, _, _, _ := setupControllerTest(t)
315 writer := httptest.NewRecorder()
316 err := e2managererrors.NewInternalError()
318 controller.handleErrorResponse(err, writer)
319 var errorResponse = parseJsonRequest(t, writer.Body)
321 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
322 assert.Equal(t, errorResponse.Code, err.Code)
323 assert.Equal(t, errorResponse.Message, err.Message)
326 func TestHandleCommandAlreadyInProgressError(t *testing.T) {
327 controller, _, _, _ := setupControllerTest(t)
328 writer := httptest.NewRecorder()
329 err := e2managererrors.NewCommandAlreadyInProgressError()
331 controller.handleErrorResponse(err, writer)
332 var errorResponse = parseJsonRequest(t, writer.Body)
334 assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
335 assert.Equal(t, errorResponse.Code, err.Code)
336 assert.Equal(t, errorResponse.Message, err.Message)
339 func TestValidateHeaders(t *testing.T) {
340 controller, _, _, _ := setupControllerTest(t)
342 header := http.Header{}
343 header.Set("Content-Type", "application/json")
344 result := controller.validateRequestHeader(&header)
346 assert.Nil(t, result)
349 func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse {
351 var errorResponse models.ErrorResponse
352 body, err := ioutil.ReadAll(r)
354 t.Errorf("Error cannot deserialize json request")
356 json.Unmarshal(body, &errorResponse)
361 func initLog(t *testing.T) *logger.Logger {
362 log, err := logger.InitLogger(logger.InfoLevel)
364 t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err)
369 func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) {
370 controller, readerMock, _, rmrMessengerMock := setupControllerTest(t)
373 payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40}
375 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
376 rmrMessengerMock.On("SendMsg", msg, mock.Anything).Return(msg, nil)
378 writer := httptest.NewRecorder()
380 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
381 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
383 data4Req := map[string]interface{}{"cause": "protocol:transfer-syntax-error"}
384 b := new(bytes.Buffer)
385 _ = json.NewEncoder(b).Encode(data4Req)
386 req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
387 req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
389 controller.X2Reset(writer, req)
390 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
394 func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) {
395 controller, readerMock, _, rmrMessengerMock := setupControllerTest(t)
399 payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64}
401 msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction)
402 rmrMessengerMock.On("SendMsg", msg).Return(msg, nil)
404 writer := httptest.NewRecorder()
406 var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
407 readerMock.On("GetNodeb", ranName).Return(nodeb, nil)
410 b := new(bytes.Buffer)
411 req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
412 req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
414 controller.X2Reset(writer, req)
415 assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode)
419 func TestX2ResetHandleFailureInvalidBody(t *testing.T) {
420 controller, _, _, _ := setupControllerTest(t)
424 writer := httptest.NewRecorder()
426 // Invalid json: attribute name without quotes (should be "cause":).
427 b := strings.NewReader("{cause:\"protocol:transfer-syntax-error\"")
428 req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b)
429 req = mux.SetURLVars(req, map[string]string{"ranName": ranName})
431 controller.X2Reset(writer, req)
432 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
436 func TestHandleErrorResponse(t *testing.T) {
437 controller, _, _, _ := setupControllerTest(t)
439 writer := httptest.NewRecorder()
440 controller.handleErrorResponse(e2managererrors.NewRnibDbError(), writer)
441 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
443 writer = httptest.NewRecorder()
444 controller.handleErrorResponse(e2managererrors.NewCommandAlreadyInProgressError(), writer)
445 assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode)
447 writer = httptest.NewRecorder()
448 controller.handleErrorResponse(e2managererrors.NewHeaderValidationError(), writer)
449 assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode)
451 writer = httptest.NewRecorder()
452 controller.handleErrorResponse(e2managererrors.NewWrongStateError("", ""), writer)
453 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
455 writer = httptest.NewRecorder()
456 controller.handleErrorResponse(e2managererrors.NewRequestValidationError(), writer)
457 assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode)
459 writer = httptest.NewRecorder()
460 controller.handleErrorResponse(e2managererrors.NewRmrError(), writer)
461 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
463 writer = httptest.NewRecorder()
464 controller.handleErrorResponse(e2managererrors.NewResourceNotFoundError(), writer)
465 assert.Equal(t, http.StatusNotFound, writer.Result().StatusCode)
467 writer = httptest.NewRecorder()
468 controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer)
469 assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
472 func getRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender {
473 rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock)
474 rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger)
475 return rmrsender.NewRmrSender(log, rmrMessenger)