From: Irina Date: Mon, 18 Nov 2019 11:59:33 +0000 (+0200) Subject: [RICPLT-2483] New resource status request handler X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F40%2F1640%2F1;p=ric-plt%2Fresource-status-manager.git [RICPLT-2483] New resource status request handler Change-Id: I97cf7eac0acee41cc0aae7715cc23cad9c4c81de Signed-off-by: Irina --- diff --git a/RSM/app/main.go b/RSM/app/main.go index 854470e..73da3ff 100644 --- a/RSM/app/main.go +++ b/RSM/app/main.go @@ -29,6 +29,7 @@ import ( "rsm/httpserver" "rsm/logger" "rsm/managers/rmrmanagers" + "rsm/providers/httpmsghandlerprovider" "rsm/rmrcgo" "rsm/rsmdb" "rsm/services" @@ -70,8 +71,8 @@ func main() { defer rmrMessenger.Close() go rmrReceiver.ListenAndHandle() - //handlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(logger, rmrSender, config, rnibDataService) + handlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(logger, rnibDataService, resourceStatusService) rootController := controllers.NewRootController(rnibDataService) - //controller := controllers.NewController(logger, handlerProvider) - _ = httpserver.Run(config.Http.Port, rootController) -} + controller := controllers.NewController(logger, handlerProvider) + _ = httpserver.Run(config.Http.Port, rootController, controller) +} \ No newline at end of file diff --git a/RSM/controllers/controller.go b/RSM/controllers/controller.go index 9194279..5e0b509 100644 --- a/RSM/controllers/controller.go +++ b/RSM/controllers/controller.go @@ -17,10 +17,6 @@ package controllers -type IController interface { -} - -/* import ( "encoding/json" "io" @@ -39,6 +35,7 @@ const ( ) type IController interface { + ResourceStatus(writer http.ResponseWriter, r *http.Request) } type Controller struct { @@ -53,6 +50,18 @@ func NewController(logger *logger.Logger, handlerProvider *httpmsghandlerprovide } } +func (c *Controller) ResourceStatus(writer http.ResponseWriter, r *http.Request) { + c.logger.Infof("[Client -> RSM] #Controller.ResourceStatus - request: %v", c.prettifyRequest(r)) + + request := models.ResourceStatusRequest{} + + if !c.extractJsonBody(r, &request, writer) { + return + } + + c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ResourceStatusRequest, request, true) +} + func (c *Controller) extractJsonBody(r *http.Request, request models.Request, writer http.ResponseWriter) bool { defer r.Body.Close() body, err := ioutil.ReadAll(io.LimitReader(r.Body, LimitRequest)) @@ -91,29 +100,15 @@ func (c *Controller) handleRequest(writer http.ResponseWriter, header *http.Head return } - response, err := (*handler).Handle(request) - - if err != nil { - c.handleErrorResponse(err, writer) - return - } - - if response == nil { - writer.WriteHeader(http.StatusNoContent) - c.logger.Infof("[RSM -> Client] #Controller.handleRequest - status response: %v", http.StatusNoContent) - return - } - - result, err := response.Marshal() + err = handler.Handle(request) if err != nil { c.handleErrorResponse(err, writer) return } - c.logger.Infof("[RSM -> Client] #Controller.handleRequest - response: %s", result) - writer.Header().Set("Content-Type", "application/json") - writer.Write([]byte(result)) + writer.WriteHeader(http.StatusNoContent) + c.logger.Infof("[RSM -> Client] #Controller.handleRequest - status response: %v", http.StatusNoContent) } func (c *Controller) validateRequestHeader(header *http.Header) error { @@ -157,6 +152,10 @@ func (c *Controller) handleErrorResponse(err error, writer http.ResponseWriter) e2Error, _ := err.(*rsmerrors.RmrError) errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} httpError = http.StatusInternalServerError + case *rsmerrors.RsmError: + e2Error, _ := err.(*rsmerrors.RsmError) + errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} + httpError = http.StatusInternalServerError case *rsmerrors.ResourceNotFoundError: e2Error, _ := err.(*rsmerrors.ResourceNotFoundError) errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} @@ -179,11 +178,9 @@ func (c *Controller) handleErrorResponse(err error, writer http.ResponseWriter) if err != nil { c.logger.Errorf("#Controller.handleErrorResponse - Cannot send response. writer:%v", writer) } -}*/ -/* +} func (c *Controller) prettifyRequest(request *http.Request) string { dump, _ := httputil.DumpRequest(request, true) requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1) return strings.Replace(requestPrettyPrint, "\n", "", -1) -} -*/ +} \ No newline at end of file diff --git a/RSM/controllers/controller_test.go b/RSM/controllers/controller_test.go index 40af65f..55b02ac 100644 --- a/RSM/controllers/controller_test.go +++ b/RSM/controllers/controller_test.go @@ -17,37 +17,129 @@ package controllers -/* import ( "encoding/json" "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "io" "io/ioutil" "net/http" "net/http/httptest" "rsm/configuration" + "rsm/enums" + "rsm/logger" "rsm/mocks" "rsm/models" "rsm/providers/httpmsghandlerprovider" "rsm/rsmerrors" - "rsm/tests/testhelper" + "rsm/services" + "rsm/tests" + "strings" "testing" ) -func setupControllerTest(t *testing.T) (*Controller, *mocks.RnibReaderMock, *mocks.RmrMessengerMock) { - config := configuration.ParseConfiguration() +func setupControllerTest(t *testing.T) (*Controller, *mocks.RnibReaderMock, *mocks.RsmReaderMock, *mocks.RsmWriterMock, *mocks.ResourceStatusServiceMock) { + log, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } - rmrMessengerMock := &mocks.RmrMessengerMock{} - readerMock := &mocks.RnibReaderMock{} - rnibDataService, rmrSender, log := testhelper.InitTestCase(t) - handlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(log, rmrSender, config, rnibDataService) + config, err := configuration.ParseConfiguration() + if err != nil { + t.Errorf("#... - failed to parse configuration error: %s", err) + } + + resourceStatusServiceMock := &mocks.ResourceStatusServiceMock{} + rnibReaderMock := &mocks.RnibReaderMock{} + rsmReaderMock := &mocks.RsmReaderMock{} + rsmWriterMock := &mocks.RsmWriterMock{} + + rnibDataService := services.NewRnibDataService(log, config, rnibReaderMock, rsmReaderMock, rsmWriterMock) + handlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(log, rnibDataService, resourceStatusServiceMock) controller := NewController(log, handlerProvider) - return controller, readerMock, rmrMessengerMock + return controller, rnibReaderMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock +} + +func TestResourceStatusInvalidBody(t *testing.T) { + controller, _, _, _ , _:= setupControllerTest(t) + + header := http.Header{} + header.Set("Content-Type", "application/json") + httpRequest, _ := http.NewRequest("PUT", "http://localhost:4800/v1/general/resourcestatus", strings.NewReader("{}{}")) + httpRequest.Header = header + + writer := httptest.NewRecorder() + controller.ResourceStatus(writer, httpRequest) + + var errorResponse = parseJsonRequest(t, writer.Body) + + assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode) + assert.Equal(t, rsmerrors.NewInvalidJsonError().Code, errorResponse.Code) +} + +func TestResourceStatusSuccess(t *testing.T) { + controller, readerMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock := setupControllerTest(t) + + cellId1 := "02f829:0007ab00" + cellId2 := "02f829:0007ab50" + nodebInfo := &entities.NodebInfo{ + RanName: tests.RanName, + ConnectionStatus: entities.ConnectionStatus_CONNECTED, + Configuration: &entities.NodebInfo_Enb{ + Enb: &entities.Enb{ + ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}}, + }, + }, + } + var nbIdentityList []*entities.NbIdentity + config := tests.GetRsmGeneralConfiguration(true) + + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + readerMock.On("GetListEnbIds").Return(nbIdentityList, nil) + readerMock.On("GetNodeb", tests.RanName).Return(nodebInfo) + resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil) + + header := http.Header{} + header.Set("Content-Type", "application/json") + httpRequest, _ := http.NewRequest("PUT", "http://localhost:4800/v1/general/resourcestatus", strings.NewReader("{\"enableResourceStatus\":true}")) + httpRequest.Header = header + + writer := httptest.NewRecorder() + controller.ResourceStatus(writer, httpRequest) + + readerMock.AssertNumberOfCalls(t, "GetListEnbIds", 1) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0) + + assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode) +} + +func TestResourceStatusFail(t *testing.T) { + + controller, readerMock, rsmReaderMock, _, resourceStatusServiceMock := setupControllerTest(t) + + rnibErr := &rsmerrors.RnibDbError{} + + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), rnibErr) + + header := http.Header{} + header.Set("Content-Type", "application/json") + httpRequest, _ := http.NewRequest("PUT", "http://localhost:4800/v1/general/resourcestatus", strings.NewReader("{\"enableResourceStatus\":true}")) + httpRequest.Header = header + + writer := httptest.NewRecorder() + controller.ResourceStatus(writer, httpRequest) + + readerMock.AssertNumberOfCalls(t, "GetListEnbIds", 0) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0) + + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) } func TestHeaderValidationFailed(t *testing.T) { - controller, _, _ := setupControllerTest(t) + controller, _, _ ,_ , _:= setupControllerTest(t) writer := httptest.NewRecorder() header := &http.Header{} @@ -59,9 +151,9 @@ func TestHeaderValidationFailed(t *testing.T) { assert.Equal(t, errorResponse.Code, err.Code) assert.Equal(t, errorResponse.Message, err.Message) } -*/ -/*func TestHandleInternalError(t *testing.T) { - controller, _, _ := setupControllerTest(t) + +func TestHandleInternalError(t *testing.T) { + controller, _, _,_ ,_ := setupControllerTest(t) writer := httptest.NewRecorder() err := rsmerrors.NewInternalError() @@ -72,10 +164,10 @@ func TestHeaderValidationFailed(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) assert.Equal(t, errorResponse.Code, err.Code) assert.Equal(t, errorResponse.Message, err.Message) -}*/ +} -/*func TestValidateHeadersSuccess(t *testing.T) { - controller, _, _ := setupControllerTest(t) +func TestValidateHeadersSuccess(t *testing.T) { + controller, _, _,_ ,_ := setupControllerTest(t) header := http.Header{} header.Set("Content-Type", "application/json") @@ -83,8 +175,8 @@ func TestHeaderValidationFailed(t *testing.T) { assert.Nil(t, result) } -*/ -/*func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse { + +func parseJsonRequest(t *testing.T, r io.Reader) models.ErrorResponse { var errorResponse models.ErrorResponse body, err := ioutil.ReadAll(r) @@ -94,10 +186,10 @@ func TestHeaderValidationFailed(t *testing.T) { json.Unmarshal(body, &errorResponse) return errorResponse -}*/ -/* +} + func TestHandleErrorResponse(t *testing.T) { - controller, _, _ := setupControllerTest(t) + controller, _, _ ,_ , _:= setupControllerTest(t) writer := httptest.NewRecorder() controller.handleErrorResponse(rsmerrors.NewRnibDbError(), writer) @@ -130,5 +222,8 @@ func TestHandleErrorResponse(t *testing.T) { writer = httptest.NewRecorder() controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer) assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) -} -*/ + + writer = httptest.NewRecorder() + controller.handleErrorResponse(rsmerrors.NewRsmError(2), writer) + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) +} \ No newline at end of file diff --git a/RSM/enums/message_direction.go b/RSM/enums/message_direction.go index eb4b703..cf48dca 100644 --- a/RSM/enums/message_direction.go +++ b/RSM/enums/message_direction.go @@ -30,12 +30,6 @@ var messageDirectionEnumName = map[int32]string{ 2: "RIC_TO_RAN", } -const ( - UNKNOWN_MESSAGE_DIRECTION MessageDirection = 0 - RAN_TO_RIC MessageDirection = 1 - RIC_TO_RAN MessageDirection = 2 -) - func (md MessageDirection) String() string { s, ok := messageDirectionEnumName[int32(md)] if ok { diff --git a/RSM/enums/registration_request.go b/RSM/enums/registration_request.go index 5fcc67a..4dc7341 100644 --- a/RSM/enums/registration_request.go +++ b/RSM/enums/registration_request.go @@ -23,6 +23,4 @@ type Registration_Request int const ( Registration_Request_start Registration_Request = iota Registration_Request_stop - Registration_Request_partial_stop - Registration_Request_add ) diff --git a/RSM/handlers/httpmsghandlers/request_handler.go b/RSM/handlers/httpmsghandlers/request_handler.go index 7c315c9..72bdef2 100644 --- a/RSM/handlers/httpmsghandlers/request_handler.go +++ b/RSM/handlers/httpmsghandlers/request_handler.go @@ -22,5 +22,5 @@ import ( ) type RequestHandler interface { - Handle(request models.Request) (models.IResponse, error) -} + Handle(request models.Request) error +} \ No newline at end of file diff --git a/RSM/handlers/httpmsghandlers/resource_status_request_handler.go b/RSM/handlers/httpmsghandlers/resource_status_request_handler.go new file mode 100644 index 0000000..77b3f30 --- /dev/null +++ b/RSM/handlers/httpmsghandlers/resource_status_request_handler.go @@ -0,0 +1,160 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package httpmsghandlers + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "rsm/enums" + "rsm/logger" + "rsm/models" + "rsm/rsmerrors" + "rsm/services" +) + +type ResourceStatusRequestHandler struct { + rNibDataService services.RNibDataService + logger *logger.Logger + resourceStatusService services.IResourceStatusService +} + +func NewResourceStatusRequestHandler(logger *logger.Logger, rNibDataService services.RNibDataService, resourceStatusService services.IResourceStatusService) *ResourceStatusRequestHandler { + return &ResourceStatusRequestHandler{ + resourceStatusService: resourceStatusService, + rNibDataService: rNibDataService, + logger: logger, + } +} + +func (h ResourceStatusRequestHandler) Handle(request models.Request) error { + + resourceStatusRequest := request.(models.ResourceStatusRequest) + config, err := h.rNibDataService.GetRsmGeneralConfiguration() + if err != nil { + return rsmerrors.NewRnibDbError() + } + + config.EnableResourceStatus = resourceStatusRequest.EnableResourceStatus + err = h.rNibDataService.SaveRsmGeneralConfiguration(config) + if err != nil { + return rsmerrors.NewRnibDbError() + } + + nbIdentityList, err := h.rNibDataService.GetListEnbIds() + if err != nil { + return rsmerrors.NewRnibDbError() + } + + numberOfFails := 0 + for _, nbIdentity := range nbIdentityList { + + nodeb, err := h.rNibDataService.GetNodeb((*nbIdentity).GetInventoryName()) + if err != nil { + numberOfFails++ + continue + } + + if nodeb.ConnectionStatus != entities.ConnectionStatus_CONNECTED { + h.logger.Infof("#ResourceStatusRequestHandler.Handle - RAN name: %s - connection status not CONNECTED, ignore", nodeb.RanName) + numberOfFails++ + continue + } + + err = h.saveAndSendRsmRanInfo(nodeb, config) + if err != nil { + numberOfFails++ + } + } + + if numberOfFails > 0 { + return rsmerrors.NewRsmError(numberOfFails) + } + return nil +} + +func (h ResourceStatusRequestHandler) saveAndSendRsmRanInfo(nodebInfo *entities.NodebInfo, config *models.RsmGeneralConfiguration) error { + + rsmRanInfo, err := h.rNibDataService.GetRsmRanInfo(nodebInfo.RanName) + if err != nil { + return err + } + + if config.EnableResourceStatus { + err := h.handleNotStartedRsmRanInfo(nodebInfo, rsmRanInfo, config) + return err + } + + //err = h.handleNotStoppedRsmRanInfo(nodebInfo, rsmRanInfo, config) + return nil +} + +/*func (h ResourceStatusRequestHandler) handleNotStoppedRsmRanInfo(nodebInfo *entities.NodebInfo, rsmRanInfo *models.RsmRanInfo, config *models.RsmGeneralConfiguration) error { + if rsmRanInfo.Action == enums.Stop && rsmRanInfo.ActionStatus { + return nil + } + + if rsmRanInfo.Action != enums.Stop { + + err := h.saveRsmRanInfoStopFalse(rsmRanInfo) + if err != nil { + return err + } + } + + err := h.resourceStatusService.BuildAndSendStopRequest(config, rsmRanInfo.RanName, rsmRanInfo.Enb1MeasurementId, rsmRanInfo.Enb2MeasurementId) + return err +}*/ + +func (h ResourceStatusRequestHandler) handleNotStartedRsmRanInfo(nodebInfo *entities.NodebInfo, rsmRanInfo *models.RsmRanInfo, config *models.RsmGeneralConfiguration) error { + if rsmRanInfo.Action == enums.Start && rsmRanInfo.ActionStatus { + return nil + } + + if rsmRanInfo.Action != enums.Start { + + err := h.saveRsmRanInfoStartFalse(rsmRanInfo) + if err != nil { + return err + } + } + + err := h.resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, config, rsmRanInfo.Enb1MeasurementId) + return err +} + +/*func (h ResourceStatusRequestHandler) saveRsmRanInfoStopFalse(rsmRanInfo *models.RsmRanInfo) error { + rsmRanInfo.Action = enums.Stop + rsmRanInfo.ActionStatus = false + + err := h.rNibDataService.SaveRsmRanInfo(rsmRanInfo) + if err != nil { + h.logger.Errorf("#ResourceStatusRequestHandler.saveRsmRanInfoStopFalse - failed to save rsm ran data to RNIB. Error: %s", err.Error()) + return err + } + return nil +}*/ + +func (h ResourceStatusRequestHandler) saveRsmRanInfoStartFalse(rsmRanInfo *models.RsmRanInfo) error { + rsmRanInfo.Action = enums.Start + rsmRanInfo.ActionStatus = false + rsmRanInfo.Enb2MeasurementId = 0 + + err := h.rNibDataService.SaveRsmRanInfo(rsmRanInfo) + if err != nil { + return err + } + return nil +} diff --git a/RSM/handlers/httpmsghandlers/resource_status_request_handler_test.go b/RSM/handlers/httpmsghandlers/resource_status_request_handler_test.go new file mode 100644 index 0000000..dfe62cd --- /dev/null +++ b/RSM/handlers/httpmsghandlers/resource_status_request_handler_test.go @@ -0,0 +1,285 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package httpmsghandlers_test + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "rsm/configuration" + "rsm/enums" + "rsm/handlers/httpmsghandlers" + "rsm/logger" + "rsm/mocks" + "rsm/models" + "rsm/rsmerrors" + "rsm/services" + "rsm/tests" + "testing" +) + +func initTest(t *testing.T) (*httpmsghandlers.ResourceStatusRequestHandler, *mocks.RnibReaderMock, *mocks.RsmReaderMock, *mocks.RsmWriterMock, *mocks.ResourceStatusServiceMock) { + log, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } + + config, err := configuration.ParseConfiguration() + if err != nil { + t.Errorf("#... - failed to parse configuration error: %s", err) + } + + resourceStatusServiceMock := &mocks.ResourceStatusServiceMock{} + rnibReaderMock := &mocks.RnibReaderMock{} + rsmReaderMock := &mocks.RsmReaderMock{} + rsmWriterMock := &mocks.RsmWriterMock{} + + rnibDataService := services.NewRnibDataService(log, config, rnibReaderMock, rsmReaderMock, rsmWriterMock) + handler := httpmsghandlers.NewResourceStatusRequestHandler(log, rnibDataService, resourceStatusServiceMock) + + return handler, rnibReaderMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock +} + +func TestResourceStatusRequestHandlerGetConfigError(t *testing.T) { + + handler, _, rsmReaderMock, _, _ := initTest(t) + + err := common.NewInternalError(errors.New("Error")) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), err) + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + rsmReaderMock.AssertNumberOfCalls(t, "SaveRsmGeneralConfiguration", 0) + + assert.Equal(t, actualErr, rsmerrors.NewRnibDbError()) +} + +func TestResourceStatusRequestHandlerSaveConfigError(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, _ := initTest(t) + + err := common.NewInternalError(errors.New("Error")) + config := tests.GetRsmGeneralConfiguration(true) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(err) + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetListEnbIds", 0) + + assert.Equal(t, actualErr, rsmerrors.NewRnibDbError()) +} + +func TestResourceStatusRequestHandleGetListEnbIdsError(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, _ := initTest(t) + + err := common.NewInternalError(errors.New("Error")) + config := tests.GetRsmGeneralConfiguration(true) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + + var nbIdentityList []*entities.NbIdentity + readerMock.On("GetListEnbIds").Return(nbIdentityList, err) + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetNodeb", 0) + + assert.Equal(t, actualErr, rsmerrors.NewRnibDbError()) +} + +func TestResourceStatusRequestHandlerTrueStartSuccess(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock := initTest(t) + + config := tests.GetRsmGeneralConfiguration(true) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + + nbIdentityList := CreateIdentityList() + readerMock.On("GetListEnbIds").Return(nbIdentityList, nil) + + nb1 := &entities.NodebInfo{RanName: "RanName_1", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb2 := &entities.NodebInfo{RanName: "RanName_2", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb3 := &entities.NodebInfo{RanName: "RanName_3", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + readerMock.On("GetNodeb", "RanName_1").Return(nb1, nil) + readerMock.On("GetNodeb", "RanName_2").Return(nb2, nil) + readerMock.On("GetNodeb", "RanName_3").Return(nb3, nil) + + rrInfo1 := &models.RsmRanInfo{RanName:"RanName_1", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:false} + rrInfo2 := &models.RsmRanInfo{RanName:"RanName_2", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:true} + rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Stop, ActionStatus:false} + rsmReaderMock.On("GetRsmRanInfo", "RanName_1").Return(rrInfo1, nil) + rsmReaderMock.On("GetRsmRanInfo", "RanName_2").Return(rrInfo2, nil) + rsmReaderMock.On("GetRsmRanInfo", "RanName_3").Return(rrInfo3, nil) + + rsmWriterMock.On("SaveRsmRanInfo", rrInfo3).Return(nil) + + resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nb1, config, enums.Enb1MeasurementId).Return(nil) + resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nb3, config, enums.Enb1MeasurementId).Return(nil) + + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetNodeb", 3) + rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 2) + + assert.Equal(t, actualErr, nil) +} + +func TestResourceStatusRequestHandlerTrueNumberOfFails2(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock := initTest(t) + + config := tests.GetRsmGeneralConfiguration(true) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + + nbIdentityList := CreateIdentityList() + readerMock.On("GetListEnbIds").Return(nbIdentityList, nil) + + nb1 := &entities.NodebInfo{RanName: "RanName_1", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb2 := &entities.NodebInfo{RanName: "RanName_2", ConnectionStatus: entities.ConnectionStatus_DISCONNECTED,} + nb3 := &entities.NodebInfo{RanName: "RanName_3", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + readerMock.On("GetNodeb", "RanName_1").Return(nb1, nil) + readerMock.On("GetNodeb", "RanName_2").Return(nb2, nil) + readerMock.On("GetNodeb", "RanName_3").Return(nb3, nil) + + err := common.NewInternalError(errors.New("Error")) + rrInfo1 := &models.RsmRanInfo{RanName:"RanName_1", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:false} + rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Stop, ActionStatus:false} + rsmReaderMock.On("GetRsmRanInfo", "RanName_1").Return(rrInfo1, err) + rsmReaderMock.On("GetRsmRanInfo", "RanName_3").Return(rrInfo3, nil) + + rsmWriterMock.On("SaveRsmRanInfo", rrInfo3).Return(nil) + + resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nb3, mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil) + + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetNodeb", 3) + rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 1) + + rsmError := rsmerrors.NewRsmError(2) + assert.Equal(t, actualErr, rsmError) + assert.Equal(t, actualErr.Error(), rsmError.Error()) +} + +func TestResourceStatusRequestHandlerTrueNumberOfFails3(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock := initTest(t) + + config := tests.GetRsmGeneralConfiguration(true) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + + nbIdentityList := CreateIdentityList() + readerMock.On("GetListEnbIds").Return(nbIdentityList, nil) + + err := common.NewInternalError(errors.New("Error")) + nb1 := &entities.NodebInfo{RanName: "RanName_1", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb2 := &entities.NodebInfo{RanName: "RanName_2", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb3 := &entities.NodebInfo{RanName: "RanName_3", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + readerMock.On("GetNodeb", "RanName_1").Return(nb1, nil) + readerMock.On("GetNodeb", "RanName_2").Return(nb2, err) + readerMock.On("GetNodeb", "RanName_3").Return(nb3, nil) + + rrInfo1 := &models.RsmRanInfo{RanName:"RanName_1", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:false} + rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Stop, ActionStatus:false} + rsmReaderMock.On("GetRsmRanInfo", "RanName_1").Return(rrInfo1, nil) + rsmReaderMock.On("GetRsmRanInfo", "RanName_3").Return(rrInfo3, nil) + + rsmWriterMock.On("SaveRsmRanInfo", rrInfo3).Return(err) + + resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nb1, mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(errors.New("Error")) + + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetNodeb", 3) + rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 1) + + rsmError := rsmerrors.NewRsmError(3) + assert.Equal(t, actualErr, rsmError) + assert.Equal(t, actualErr.Error(), rsmError.Error()) +} + +/*func TestResourceStatusRequestHandlerFalseStopSuccess(t *testing.T) { + + handler, readerMock, rsmReaderMock, rsmWriterMock, resourceStatusServiceMock := initTest(t) + + config := tests.GetRsmGeneralConfiguration(false) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(config, nil) + rsmWriterMock.On("SaveRsmGeneralConfiguration", config).Return(nil) + + nbIdentityList := CreateIdentityList() + readerMock.On("GetListEnbIds").Return(nbIdentityList, nil) + + nb1 := &entities.NodebInfo{RanName: "RanName_1", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb2 := &entities.NodebInfo{RanName: "RanName_2", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + nb3 := &entities.NodebInfo{RanName: "RanName_3", ConnectionStatus: entities.ConnectionStatus_CONNECTED,} + readerMock.On("GetNodeb", "RanName_1").Return(nb1, nil) + readerMock.On("GetNodeb", "RanName_2").Return(nb2, nil) + readerMock.On("GetNodeb", "RanName_3").Return(nb3, nil) + + rrInfo1 := &models.RsmRanInfo{RanName:"RanName_1", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:false} + rrInfo2 := &models.RsmRanInfo{RanName:"RanName_2", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, ActionStatus:true} + rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Stop, ActionStatus:false} + rsmReaderMock.On("GetRsmRanInfo", "RanName_1").Return(rrInfo1, nil) + rsmReaderMock.On("GetRsmRanInfo", "RanName_2").Return(rrInfo2, nil) + rsmReaderMock.On("GetRsmRanInfo", "RanName_3").Return(rrInfo3, nil) + + rsmWriterMock.On("SaveRsmRanInfo", rrInfo3).Return(nil) + + resourceStatusServiceMock.On("BuildAndSendStopRequest", nb1, config, enums.Enb1MeasurementId).Return(nil) + resourceStatusServiceMock.On("BuildAndSendStopRequest", nb3, config, enums.Enb1MeasurementId).Return(nil) + + + resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:true} + actualErr := handler.Handle(resourceStatusRequest) + + readerMock.AssertNumberOfCalls(t, "GetNodeb", 3) + rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1) + resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 2) + + assert.Equal(t, actualErr, nil) +}*/ +func CreateIdentityList() []*entities.NbIdentity { + nbIdentity1 := entities.NbIdentity{InventoryName: "RanName_1"} + nbIdentity2 := entities.NbIdentity{InventoryName: "RanName_2"} + nbIdentity3 := entities.NbIdentity{InventoryName: "RanName_3"} + + var nbIdentityList []*entities.NbIdentity + nbIdentityList = append(nbIdentityList, &nbIdentity1) + nbIdentityList = append(nbIdentityList, &nbIdentity2) + nbIdentityList = append(nbIdentityList, &nbIdentity3) + + return nbIdentityList +} \ No newline at end of file diff --git a/RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go b/RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go index e9c039b..4069eb3 100644 --- a/RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go +++ b/RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go @@ -28,27 +28,13 @@ import ( "rsm/mocks" "rsm/models" "rsm/services" + "rsm/tests" "testing" "time" ) const RanName = "test" -func getRsmGeneralConfiguration(enableResourceStatus bool) *models.RsmGeneralConfiguration { - return &models.RsmGeneralConfiguration{ - EnableResourceStatus: enableResourceStatus, - PartialSuccessAllowed: true, - PrbPeriodic: true, - TnlLoadIndPeriodic: true, - HwLoadIndPeriodic: true, - AbsStatusPeriodic: true, - RsrpMeasurementPeriodic: true, - CsiPeriodic: true, - PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, - PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, - PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, - } -} func initRanConnectedNotificationHandlerTest(t *testing.T, requestName string) (ResourceStatusInitiateNotificationHandler, *mocks.RnibReaderMock, *mocks.ResourceStatusServiceMock, *mocks.RsmWriterMock, *mocks.RsmReaderMock) { log, err := logger.InitLogger(logger.DebugLevel) @@ -134,7 +120,7 @@ func TestGetRsmGeneralConfigurationFailure(t *testing.T) { func TestEnableResourceStatusFalse(t *testing.T) { h, _, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected") var err error - rsmReaderMock.On("GetRsmGeneralConfiguration").Return(getRsmGeneralConfiguration(false), err) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(false), err) rsmRanInfo := models.RsmRanInfo{RanName, 0, 0, enums.Stop, true} rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(err) @@ -151,7 +137,7 @@ func TestEnableResourceStatusFalse(t *testing.T) { func TestEnableResourceStatusFalseSaveRsmRanInfoFailure(t *testing.T) { h, _, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected") var err error - rsmReaderMock.On("GetRsmGeneralConfiguration").Return(getRsmGeneralConfiguration(false), err) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(false), err) rsmRanInfo := models.RsmRanInfo{RanName, 0, 0, enums.Stop, true} rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(common.NewInternalError(errors.New("Error"))) @@ -173,7 +159,7 @@ func TestGetNodebFailure(t *testing.T) { rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()} var err error - rsmReaderMock.On("GetRsmGeneralConfiguration").Return(getRsmGeneralConfiguration(true), err) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), err) var nodebInfo *entities.NodebInfo rnibReaderMock.On("GetNodeb", RanName).Return(nodebInfo, common.NewInternalError(errors.New("Error"))) @@ -187,7 +173,7 @@ func TestGetNodebFailure(t *testing.T) { func TestInvalidConnectionStatus(t *testing.T) { h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected") var err error - rsmReaderMock.On("GetRsmGeneralConfiguration").Return(getRsmGeneralConfiguration(true), err) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), err) rnibReaderMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED}, err) rsmRanInfo := models.RsmRanInfo{RanName, 0, 0, enums.Stop, true} rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(err) @@ -211,7 +197,7 @@ func TestEnableResourceStatusTrueSaveRsmRanInfoFailure(t *testing.T) { rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()} var err error - rsmReaderMock.On("GetRsmGeneralConfiguration").Return(getRsmGeneralConfiguration(true), err) + rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), err) rnibReaderMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}, err) rsmRanInfo := models.RsmRanInfo{RanName, enums.Enb1MeasurementId, 0, enums.Start, false} rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(common.NewInternalError(errors.New("Error"))) @@ -231,7 +217,7 @@ func TestBuildAndSendSuccess(t *testing.T) { rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()} var err error - rgc := getRsmGeneralConfiguration(true) + rgc := tests.GetRsmGeneralConfiguration(true) rsmReaderMock.On("GetRsmGeneralConfiguration").Return(rgc, err) nodebInfo := &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED} rnibReaderMock.On("GetNodeb", RanName).Return(nodebInfo, err) @@ -250,7 +236,7 @@ func TestBuildAndSendError(t *testing.T) { h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected") var err error nodebInfo := &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED} - rgc := getRsmGeneralConfiguration(true) + rgc := tests.GetRsmGeneralConfiguration(true) rsmReaderMock.On("GetRsmGeneralConfiguration").Return(rgc, err) rnibReaderMock.On("GetNodeb", RanName).Return(nodebInfo, err) rsmRanInfoStart := models.RsmRanInfo{RanName, enums.Enb1MeasurementId, 0, enums.Start, false} diff --git a/RSM/httpserver/http_server.go b/RSM/httpserver/http_server.go index f281a95..b92f8a9 100644 --- a/RSM/httpserver/http_server.go +++ b/RSM/httpserver/http_server.go @@ -24,10 +24,10 @@ import ( "rsm/controllers" ) -func Run(port int, controller controllers.IRootController) error { +func Run(port int, rootController controllers.IRootController, controller controllers.IController) error { router := mux.NewRouter() - initializeRoutes(router, controller) + initializeRoutes(router, rootController, controller) addr := fmt.Sprintf(":%d", port) @@ -36,7 +36,10 @@ func Run(port int, controller controllers.IRootController) error { return fmt.Errorf("#http_server.Run - Fail initiating HTTP server. Error: %v", err) } -func initializeRoutes(router *mux.Router, rootController controllers.IRootController) { +func initializeRoutes(router *mux.Router, rootController controllers.IRootController, controller controllers.IController) { r := router.PathPrefix("/v1").Subrouter() r.HandleFunc("/health", rootController.HandleHealthCheckRequest).Methods("GET") -} + + rr := r.PathPrefix("/general").Subrouter() + rr.HandleFunc("/resourcestatus", controller.ResourceStatus).Methods("PUT") +} \ No newline at end of file diff --git a/RSM/httpserver/http_server_test.go b/RSM/httpserver/http_server_test.go index 26bc243..4f2057c 100644 --- a/RSM/httpserver/http_server_test.go +++ b/RSM/httpserver/http_server_test.go @@ -27,17 +27,32 @@ import ( "time" ) -func setupRouterAndMocks() (*mux.Router, *mocks.RootControllerMock) { +func setupRouterAndMocks() (*mux.Router, *mocks.RootControllerMock, *mocks.ControllerMock) { rootControllerMock := &mocks.RootControllerMock{} rootControllerMock.On("HandleHealthCheckRequest").Return(nil) + controllerMock := &mocks.ControllerMock{} + controllerMock.On("ResourceStatus").Return(nil) + router := mux.NewRouter() - initializeRoutes(router, rootControllerMock) - return router, rootControllerMock + initializeRoutes(router, rootControllerMock, controllerMock) + return router, rootControllerMock, controllerMock +} +func TestResourceStatus(t *testing.T) { + router, _, controllerMock := setupRouterAndMocks() + + req, err := http.NewRequest("PUT", "/v1/general/resourcestatus", nil) + if err != nil { + t.Fatal(err) + } + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + + controllerMock.AssertNumberOfCalls(t, "ResourceStatus", 1) } func TestRouteGetHealth(t *testing.T) { - router, rootControllerMock := setupRouterAndMocks() + router, rootControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/health", nil) if err != nil { @@ -50,7 +65,7 @@ func TestRouteGetHealth(t *testing.T) { } func TestRouteNotFound(t *testing.T) { - router, _ := setupRouterAndMocks() + router, _, _ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/no/such/route", nil) if err != nil { @@ -63,18 +78,17 @@ func TestRouteNotFound(t *testing.T) { } func TestRunError(t *testing.T) { - rootControllerMock := &mocks.RootControllerMock{} + _, rootControllerMock, controllerMock := setupRouterAndMocks() - err := Run(111222333, rootControllerMock) + err := Run(111222333, rootControllerMock, controllerMock) assert.NotNil(t, err) } func TestRun(t *testing.T) { - rootControllerMock := &mocks.RootControllerMock{} - rootControllerMock.On("HandleHealthCheckRequest").Return(nil) + _, rootControllerMock, controllerMock := setupRouterAndMocks() - go Run(11223, rootControllerMock) + go Run(11223, rootControllerMock, controllerMock) time.Sleep(time.Millisecond * 100) resp, err := http.Get("http://localhost:11223/v1/health") @@ -82,4 +96,4 @@ func TestRun(t *testing.T) { t.Fatalf("failed to perform GET to http://localhost:11223/v1/health") } assert.Equal(t, 200, resp.StatusCode) -} +} \ No newline at end of file diff --git a/RSM/mocks/controller_mock.go b/RSM/mocks/controller_mock.go index d860857..36cf4a6 100644 --- a/RSM/mocks/controller_mock.go +++ b/RSM/mocks/controller_mock.go @@ -19,8 +19,16 @@ package mocks import ( "github.com/stretchr/testify/mock" + "net/http" ) type ControllerMock struct { mock.Mock } + +func (c *ControllerMock) ResourceStatus(writer http.ResponseWriter, r *http.Request){ + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + + c.Called() +} \ No newline at end of file diff --git a/RSM/models/resource_status_request.go b/RSM/models/resource_status_request.go new file mode 100644 index 0000000..e449476 --- /dev/null +++ b/RSM/models/resource_status_request.go @@ -0,0 +1,22 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package models + +type ResourceStatusRequest struct { + EnableResourceStatus bool `json:"enableResourceStatus"` +} diff --git a/RSM/providers/httpmsghandlerprovider/request_handler_provider.go b/RSM/providers/httpmsghandlerprovider/request_handler_provider.go index 7c6fa4e..599a659 100644 --- a/RSM/providers/httpmsghandlerprovider/request_handler_provider.go +++ b/RSM/providers/httpmsghandlerprovider/request_handler_provider.go @@ -17,39 +17,39 @@ package httpmsghandlerprovider import ( - "rsm/configuration" "rsm/handlers/httpmsghandlers" "rsm/logger" "rsm/rsmerrors" "rsm/services" - "rsm/services/rmrsender" ) type IncomingRequest string const ( - ResourceStatusInitiation = "ResourceStatusInitiation" + ResourceStatusRequest = "ResourceStatusRequest" ) type RequestHandlerProvider struct { - requestMap map[IncomingRequest]*httpmsghandlers.RequestHandler + requestMap map[IncomingRequest]httpmsghandlers.RequestHandler logger *logger.Logger } -func NewRequestHandlerProvider(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService) *RequestHandlerProvider { +func NewRequestHandlerProvider(logger *logger.Logger, rNibDataService services.RNibDataService, resourceStatusService services.IResourceStatusService) *RequestHandlerProvider { return &RequestHandlerProvider{ - requestMap: initRequestHandlerMap(logger, rmrSender, config, rNibDataService), + requestMap: initRequestHandlerMap(logger, rNibDataService, resourceStatusService), logger: logger, } } -func initRequestHandlerMap(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService) map[IncomingRequest]*httpmsghandlers.RequestHandler { +func initRequestHandlerMap(logger *logger.Logger, rNibDataService services.RNibDataService, resourceStatusService services.IResourceStatusService) map[IncomingRequest]httpmsghandlers.RequestHandler { - return map[IncomingRequest]*httpmsghandlers.RequestHandler{} + return map[IncomingRequest]httpmsghandlers.RequestHandler{ + ResourceStatusRequest: httpmsghandlers.NewResourceStatusRequestHandler(logger, rNibDataService, resourceStatusService), + } } -func (provider RequestHandlerProvider) GetHandler(requestType IncomingRequest) (*httpmsghandlers.RequestHandler, error) { +func (provider RequestHandlerProvider) GetHandler(requestType IncomingRequest) (httpmsghandlers.RequestHandler, error) { handler, ok := provider.requestMap[requestType] if !ok { @@ -58,4 +58,4 @@ func (provider RequestHandlerProvider) GetHandler(requestType IncomingRequest) ( } return handler, nil -} +} \ No newline at end of file diff --git a/RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go b/RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go index b3d656f..e7a01ad 100644 --- a/RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go +++ b/RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go @@ -21,18 +21,32 @@ import ( "github.com/stretchr/testify/assert" "reflect" "rsm/configuration" + "rsm/handlers/httpmsghandlers" + "rsm/logger" + "rsm/mocks" "rsm/rsmerrors" - "rsm/tests/testhelper" + "rsm/services" "testing" ) func setupTest(t *testing.T) *RequestHandlerProvider { + log, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } + config, err := configuration.ParseConfiguration() if err != nil { t.Errorf("#... - failed to parse configuration error: %s", err) } - rnibDataService, rmrSender, log := testhelper.InitTestCase(t) - return NewRequestHandlerProvider(log, rmrSender, config, rnibDataService) + + resourceStatusServiceMock := &mocks.ResourceStatusServiceMock{} + rnibReaderMock := &mocks.RnibReaderMock{} + rsmReaderMock := &mocks.RsmReaderMock{} + rsmWriterMock := &mocks.RsmWriterMock{} + + rnibDataService := services.NewRnibDataService(log, config, rnibReaderMock, rsmReaderMock, rsmWriterMock) + return NewRequestHandlerProvider(log, rnibDataService, resourceStatusServiceMock) } func TestNewRequestHandlerProvider(t *testing.T) { @@ -41,6 +55,18 @@ func TestNewRequestHandlerProvider(t *testing.T) { assert.NotNil(t, provider) } +func TestResourceStatusRequestHandler(t *testing.T) { + provider := setupTest(t) + handler, err := provider.GetHandler(ResourceStatusRequest) + + assert.NotNil(t, provider) + assert.Nil(t, err) + + _, ok := handler.(*httpmsghandlers.ResourceStatusRequestHandler) + + assert.True(t, ok) +} + func TestNewRequestHandlerProvider_InternalError(t *testing.T) { provider := setupTest(t) @@ -51,4 +77,4 @@ func TestNewRequestHandlerProvider_InternalError(t *testing.T) { if reflect.TypeOf(actual) != reflect.TypeOf(expected) { t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) } -} +} \ No newline at end of file diff --git a/RSM/services/resource_status_service.go b/RSM/services/resource_status_service.go index d10da61..974b594 100644 --- a/RSM/services/resource_status_service.go +++ b/RSM/services/resource_status_service.go @@ -35,6 +35,7 @@ type ResourceStatusService struct { type IResourceStatusService interface { BuildAndSendInitiateRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64) error + //BuildAndSendStopRequest(config *models.RsmGeneralConfiguration, ranName string, enb1MeasurementId int64, enb2MeasurementId int64) error } func NewResourceStatusService(logger *logger.Logger, rmrSender *rmrsender.RmrSender) *ResourceStatusService { @@ -67,6 +68,26 @@ func (m *ResourceStatusService) BuildAndSendInitiateRequest(nodeb *entities.Node return m.rmrSender.Send(rmrMsg) } +/*func (m *ResourceStatusService) BuildAndSendStopRequest(config *models.RsmGeneralConfiguration, ranName string, enb1MeasurementId int64, enb2MeasurementId int64) error { + + requestParams := &e2pdus.ResourceStatusRequestData{ + MeasurementID: e2pdus.Measurement_ID(enb1MeasurementId), + MeasurementID2: e2pdus.Measurement_ID(enb2MeasurementId), + } + + payload, payloadAsString, err := e2pdus.BuildPackedResourceStatusRequest(enums.Registration_Request_stop, requestParams, e2pdus.MaxAsn1PackedBufferSize, e2pdus.MaxAsn1CodecMessageBufferSize, m.logger.DebugEnabled()) + + if err != nil { + m.logger.Errorf("#ResourceStatusService.BuildAndSendStopRequest - RAN name: %s. Failed to build and pack resource status stop request. error: %s", ranName, err) + return err + } + + m.logger.Debugf("#ResourceStatusService.BuildAndSendStopRequest - RAN name: %s. Successfully build packed payload: %s", ranName, payloadAsString) + rmrMsg := models.NewRmrMessage(rmrcgo.RicResStatusReq, ranName, payload) + + return m.rmrSender.Send(rmrMsg) +}*/ + func (m *ResourceStatusService) extractCellIdList(nodeb *entities.NodebInfo) ([]string, error) { enb, ok := nodeb.Configuration.(*entities.NodebInfo_Enb) diff --git a/RSM/services/rnib_data_service.go b/RSM/services/rnib_data_service.go index 9e7d332..3f89773 100644 --- a/RSM/services/rnib_data_service.go +++ b/RSM/services/rnib_data_service.go @@ -31,10 +31,12 @@ import ( type RNibDataService interface { GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) + SaveRsmGeneralConfiguration(config *models.RsmGeneralConfiguration) error GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error) SaveRsmRanInfo(rsmData *models.RsmRanInfo) error GetNodeb(ranName string) (*entities.NodebInfo, error) GetListNodebIds() ([]*entities.NbIdentity, error) + GetListEnbIds() ([]*entities.NbIdentity, error) PingRnib() bool } @@ -73,6 +75,17 @@ func (w *rNibDataService) GetRsmGeneralConfiguration() (*models.RsmGeneralConfig return rsmGeneralConfiguration, err } +func (w *rNibDataService) SaveRsmGeneralConfiguration(config *models.RsmGeneralConfiguration) error { + w.logger.Infof("#RnibDataService.SaveRsmGeneralConfiguration - configuration: %+v", *config) + + err := w.retry("SaveRsmGeneralConfiguration", func() (err error) { + err = w.rsmWriter.SaveRsmGeneralConfiguration(config) + return + }) + + return err +} + func (w *rNibDataService) GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error) { var rsmRanInfo *models.RsmRanInfo = nil @@ -112,6 +125,19 @@ func (w *rNibDataService) GetNodeb(ranName string) (*entities.NodebInfo, error) return nodeb, err } +func (w *rNibDataService) GetListEnbIds() ([]*entities.NbIdentity, error) { + w.logger.Infof("#RnibDataService.GetListEnbIds") + + var nodeIds []*entities.NbIdentity = nil + + err := w.retry("GetListEnbIds", func() (err error) { + nodeIds, err = w.rnibReader.GetListEnbIds() + return + }) + + return nodeIds, err +} + func (w *rNibDataService) GetListNodebIds() ([]*entities.NbIdentity, error) { w.logger.Infof("#RnibDataService.GetListNodebIds") diff --git a/RSM/services/rnib_data_service_test.go b/RSM/services/rnib_data_service_test.go index dfc0e18..2bcfdd4 100644 --- a/RSM/services/rnib_data_service_test.go +++ b/RSM/services/rnib_data_service_test.go @@ -175,4 +175,4 @@ func TestPingRnibOkOtherError(t *testing.T) { res := rnibDataService.PingRnib() readerMock.AssertNumberOfCalls(t, "GetListNodebIds", 1) assert.True(t, res) -} +} \ No newline at end of file diff --git a/RSM/tests/dataProvider.go b/RSM/tests/dataProvider.go index d6a908d..cd9d795 100644 --- a/RSM/tests/dataProvider.go +++ b/RSM/tests/dataProvider.go @@ -21,6 +21,8 @@ import ( "bytes" "encoding/json" "net/http" + "rsm/enums" + "rsm/models" "strconv" ) @@ -52,3 +54,19 @@ func GetHttpRequest() *http.Request { req, _ := http.NewRequest("POST", "https://localhost:3800/request", b) return req } + +func GetRsmGeneralConfiguration(enableResourceStatus bool) *models.RsmGeneralConfiguration { + return &models.RsmGeneralConfiguration{ + EnableResourceStatus: enableResourceStatus, + PartialSuccessAllowed: true, + PrbPeriodic: true, + TnlLoadIndPeriodic: true, + HwLoadIndPeriodic: true, + AbsStatusPeriodic: true, + RsrpMeasurementPeriodic: true, + CsiPeriodic: true, + PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, + PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, + PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, + } +} \ No newline at end of file diff --git a/RSM/tests/payloadProvider.go b/RSM/tests/payloadProvider.go deleted file mode 100644 index eceea09..0000000 --- a/RSM/tests/payloadProvider.go +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright 2019 AT&T Intellectual Property -// Copyright 2019 Nokia -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tests - -// #cgo CFLAGS: -I../asn1codec/inc/ -I../asn1codec/e2ap_engine/ -// #cgo LDFLAGS: -L ../asn1codec/lib/ -L../asn1codec/e2ap_engine/ -le2ap_codec -lasncodec -// #include -// #include -// -// bool -// build_pack_x2_reset_response(size_t* packed_buf_size, unsigned char* packed_buf, size_t err_buf_size, char* err_buf){ -// bool rc = true; -// E2AP_PDU_t *pdu = calloc(1, sizeof(E2AP_PDU_t)); -// SuccessfulOutcome_t *successfulOutcome = calloc(1, sizeof(SuccessfulOutcome_t)); -// ResetResponse_t *resetResponse; -// ResetResponse_IEs_t *resetResponse_IEs = calloc(1, sizeof(ResetResponse_IEs_t)); -// -// assert(pdu != 0); -// assert(successfulOutcome != 0); -// assert(resetResponse_IEs != 0); -// -// pdu->present = E2AP_PDU_PR_successfulOutcome; -// pdu->choice.successfulOutcome = successfulOutcome; -// -// successfulOutcome->procedureCode = ProcedureCode_id_reset; -// successfulOutcome->criticality = Criticality_reject; -// successfulOutcome->value.present = SuccessfulOutcome__value_PR_ResetResponse; -// resetResponse = &successfulOutcome->value.choice.ResetResponse; -// -// CriticalityDiagnostics_IE_List_t *critList = calloc(1, sizeof(CriticalityDiagnostics_IE_List_t)); -// assert(critList != 0); -// resetResponse_IEs->id = ProtocolIE_ID_id_CriticalityDiagnostics; -// resetResponse_IEs->criticality = Criticality_ignore; -// resetResponse_IEs->value.present = ResetResponse_IEs__value_PR_CriticalityDiagnostics; -// ASN_SEQUENCE_ADD(resetResponse_IEs->value.choice.CriticalityDiagnostics.iEsCriticalityDiagnostics,critList); -// -// CriticalityDiagnostics_IE_List__Member *member= calloc(1, sizeof(CriticalityDiagnostics_IE_List__Member)); -// assert(member != 0); -// ASN_SEQUENCE_ADD(critList ,member); -// -// ASN_SEQUENCE_ADD(&resetResponse->protocolIEs, resetResponse_IEs); -// -// rc = per_pack_pdu(pdu, packed_buf_size, packed_buf,err_buf_size, err_buf); -// -// ASN_STRUCT_FREE(asn_DEF_E2AP_PDU, pdu); -// return rc; -// } -import "C" -import ( - "errors" - "fmt" - "unsafe" -) - -const PackedBufferSize = 4096 - -func BuildPackedX2ResetResponse() ([]byte, error) { - payloadSize := C.ulong(PackedBufferSize) - packedBuffer := [PackedBufferSize]C.uchar{} - errorBuffer := [PackedBufferSize]C.char{} - res := bool(C.build_pack_x2_reset_response(&payloadSize, &packedBuffer[0], PackedBufferSize, &errorBuffer[0])) - if !res { - return nil, errors.New(fmt.Sprintf("packing error: %s", C.GoString(&errorBuffer[0]))) - } - return C.GoBytes(unsafe.Pointer(&packedBuffer), C.int(payloadSize)), nil -} diff --git a/Swagger/RSM_API.yaml b/Swagger/RSM_API.yaml index c1a71ba..98ed0b0 100644 --- a/Swagger/RSM_API.yaml +++ b/Swagger/RSM_API.yaml @@ -27,7 +27,7 @@ servers: apiRoot: default: 'localhost:?' paths: - /health: + '/health': get: tags: - Health Check @@ -35,8 +35,35 @@ paths: responses: '204': description: OK + '/general/resourcestatus': + put: + summary: enable/disable resource status + tags: + - Resource Status + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceStatus' + required: true + responses: + '204': + description: Success + '500': + description: Internal error + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ErrorResponse' components: schemas: + ResourceStatus: + type: object + required: + - enableResourceStatus + properties: + enableResourceStatus: + type: boolean ErrorResponse: type: object required: @@ -45,7 +72,7 @@ components: properties: errorCode: type: string - description: '401 - corrupted json, 402 - validation error, 403 - RAN in wrong state, 404 - resource not found, 500 - RNIB error, 501 - internal problem, 502 - RMR error' + description: '401 - corrupted json, 402 - validation error, 403 - RAN in wrong state, 404 - resource not found, 500 - RNIB error, 501 - internal problem, 502 - RMR error, 503 - RSM error' errorMessage: type: string description: Human readable text