[RICPLT-2483] New resource status request handler 40/1640/1
authorIrina <ib565x@intl.att.com>
Mon, 18 Nov 2019 11:59:33 +0000 (13:59 +0200)
committerIrina <ib565x@intl.att.com>
Mon, 18 Nov 2019 11:59:45 +0000 (13:59 +0200)
Change-Id: I97cf7eac0acee41cc0aae7715cc23cad9c4c81de
Signed-off-by: Irina <ib565x@intl.att.com>
21 files changed:
RSM/app/main.go
RSM/controllers/controller.go
RSM/controllers/controller_test.go
RSM/enums/message_direction.go
RSM/enums/registration_request.go
RSM/handlers/httpmsghandlers/request_handler.go
RSM/handlers/httpmsghandlers/resource_status_request_handler.go [new file with mode: 0644]
RSM/handlers/httpmsghandlers/resource_status_request_handler_test.go [new file with mode: 0644]
RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go
RSM/httpserver/http_server.go
RSM/httpserver/http_server_test.go
RSM/mocks/controller_mock.go
RSM/models/resource_status_request.go [new file with mode: 0644]
RSM/providers/httpmsghandlerprovider/request_handler_provider.go
RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go
RSM/services/resource_status_service.go
RSM/services/rnib_data_service.go
RSM/services/rnib_data_service_test.go
RSM/tests/dataProvider.go
RSM/tests/payloadProvider.go [deleted file]
Swagger/RSM_API.yaml

index 854470e..73da3ff 100644 (file)
@@ -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
index 9194279..5e0b509 100644 (file)
 
 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
index 40af65f..55b02ac 100644 (file)
 
 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
index eb4b703..cf48dca 100644 (file)
@@ -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 {
index 5fcc67a..4dc7341 100644 (file)
@@ -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
 )
index 7c315c9..72bdef2 100644 (file)
@@ -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 (file)
index 0000000..77b3f30
--- /dev/null
@@ -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 (file)
index 0000000..dfe62cd
--- /dev/null
@@ -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
index e9c039b..4069eb3 100644 (file)
@@ -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}
index f281a95..b92f8a9 100644 (file)
@@ -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
index 26bc243..4f2057c 100644 (file)
@@ -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
index d860857..36cf4a6 100644 (file)
@@ -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 (file)
index 0000000..e449476
--- /dev/null
@@ -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"`
+}
index 7c6fa4e..599a659 100644 (file)
 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
index b3d656f..e7a01ad 100644 (file)
@@ -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
index d10da61..974b594 100644 (file)
@@ -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)
index 9e7d332..3f89773 100644 (file)
@@ -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")
 
index dfc0e18..2bcfdd4 100644 (file)
@@ -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
index d6a908d..cd9d795 100644 (file)
@@ -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 (file)
index eceea09..0000000
+++ /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 <asn1codec_utils.h>
-// #include <SuccessfulOutcome.h>
-//
-// 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
-}
index c1a71ba..98ed0b0 100644 (file)
@@ -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