Copy latest code to master 70/2070/1
authorss412g <shuky.har-noy@intl.att.com>
Wed, 18 Dec 2019 12:26:51 +0000 (14:26 +0200)
committerss412g <shuky.har-noy@intl.att.com>
Wed, 18 Dec 2019 12:26:59 +0000 (14:26 +0200)
Change-Id: I5f657e299e2c196354531cb6b7c7494552a84026
Signed-off-by: ss412g <shuky.har-noy@intl.att.com>
93 files changed:
RSM/3rdparty/asn1codec/inc/resource_status_request_wrapper.h
RSM/3rdparty/asn1codec/inc/resource_status_response_wrapper.h [new file with mode: 0644]
RSM/3rdparty/asn1codec/src/resource_status_request_wrapper.c
RSM/3rdparty/asn1codec/src/tests/resource_status_request_wrapper_test.c
RSM/Dockerfile
RSM/app/main.go
RSM/configuration/configuration.go
RSM/configuration/configuration_test.go
RSM/controllers/controller.go
RSM/controllers/controller_test.go
RSM/controllers/root_controller_test.go
RSM/converters/resource_status_failure_unpacker.go [new file with mode: 0644]
RSM/converters/resource_status_failure_unpacker_test.go [new file with mode: 0644]
RSM/converters/resource_status_response_unpacker.go [new file with mode: 0644]
RSM/converters/resource_status_response_unpacker_test.go [new file with mode: 0644]
RSM/converters/x2apPdu_asn1_unpacker.go
RSM/converters/x2apPdu_asn1_unpacker_test.go
RSM/e2pdus/resource_status_request.go
RSM/e2pdus/resource_status_request_test.go
RSM/enums/constants.go [new file with mode: 0644]
RSM/enums/message_direction.go
RSM/enums/registration_request.go
RSM/enums/reporting_periodicity.go
RSM/enums/rsm_action.go [new file with mode: 0644]
RSM/go.mod
RSM/go.sum
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_failure_handler.go
RSM/handlers/rmrmsghandlers/resource_status_failure_handler_test.go
RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler.go
RSM/handlers/rmrmsghandlers/resource_status_initiate_notification_handler_test.go
RSM/handlers/rmrmsghandlers/resource_status_response_handler.go
RSM/handlers/rmrmsghandlers/resource_status_response_handler_test.go [new file with mode: 0644]
RSM/handlers/rmrmsghandlers/rmr_message_handler.go
RSM/httpserver/http_server.go
RSM/httpserver/http_server_test.go
RSM/logger/logger.go
RSM/logger/logger_test.go
RSM/managers/resource_status_initiate_manager.go [deleted file]
RSM/managers/resource_status_initiate_manager_test.go [deleted file]
RSM/managers/rmrmanagers/rmr_message_manager.go
RSM/managers/rmrmanagers/rmr_message_manager_test.go
RSM/mocks/controller_mock.go
RSM/mocks/resource_status_failure_converter_mock.go [new file with mode: 0644]
RSM/mocks/resource_status_initiate_manager_mock.go [deleted file]
RSM/mocks/resource_status_response_converter_mock.go [new file with mode: 0644]
RSM/mocks/resource_status_service_mock.go [new file with mode: 0644]
RSM/mocks/rmr_messenger_mock.go
RSM/mocks/rnib_reader_mock.go
RSM/mocks/root_controller_mock.go
RSM/mocks/rsm_reader_mock.go [new file with mode: 0644]
RSM/mocks/rsm_writer_mock.go [moved from RSM/mocks/unpacker_mock.go with 71% similarity]
RSM/mocks/sdl_instance_mock.go
RSM/models/request_interface.go
RSM/models/resource_status_payload.go
RSM/models/resource_status_request.go [new file with mode: 0644]
RSM/models/resource_status_response.go [new file with mode: 0644]
RSM/models/response_interface.go
RSM/models/rmr_message.go
RSM/models/rmr_request.go
RSM/models/rsm_general_configuration.go [new file with mode: 0644]
RSM/models/rsm_ran_info.go [new file with mode: 0644]
RSM/providers/httpmsghandlerprovider/request_handler_provider.go
RSM/providers/httpmsghandlerprovider/request_handler_provider_test.go
RSM/providers/rmrmsghandlerprovider/message_handler_provider.go
RSM/providers/rmrmsghandlerprovider/message_handler_provider_test.go
RSM/resources/configuration.yaml
RSM/rmrcgo/rmr_c_go_api_test.go
RSM/rmrcgo/rmr_c_go_utils.go
RSM/rsmdb/rsm_reader.go [new file with mode: 0644]
RSM/rsmdb/rsm_reader_test.go [new file with mode: 0644]
RSM/rsmdb/rsm_writer.go [new file with mode: 0644]
RSM/rsmdb/rsm_writer_test.go [new file with mode: 0644]
RSM/rsmerrors/base_error.go
RSM/rsmerrors/header_validation_error.go
RSM/rsmerrors/internal_error.go
RSM/rsmerrors/invalid_json_error.go
RSM/rsmerrors/rnib_db_error.go
RSM/rsmerrors/rsm_error.go [new file with mode: 0644]
RSM/rsmerrors/wrong_state_error.go
RSM/services/resource_status_service.go [new file with mode: 0644]
RSM/services/resource_status_service_test.go [new file with mode: 0644]
RSM/services/rmrreceiver/rmr_receiver.go
RSM/services/rmrreceiver/rmr_receiver_test.go
RSM/services/rmrsender/rmr_sender.go
RSM/services/rmrsender/rmr_sender_test.go
RSM/services/rnib_data_service.go
RSM/services/rnib_data_service_test.go
RSM/tests/dataProvider.go
RSM/tests/payloadProvider.go [deleted file]
RSM/tests/testhelper/test_utils.go

index cb2683e..07d9a31 100644 (file)
@@ -37,8 +37,9 @@ extern "C"
 
 bool
 build_pack_resource_status_request(
-               uint8_t const* pLMN_Identity,
-        uint8_t const* eUTRANCellIdentifier,
+               uint8_t const** pLMN_Identities,
+        uint8_t const** eUTRANCellIdentifiers,
+        size_t nECGIs,
                Measurement_ID_t measurement_ID, Measurement_ID_t measurement_ID2,
                Registration_Request_t registration_Request /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
                uint32_t reportCharacteristics,
@@ -51,8 +52,9 @@ build_pack_resource_status_request(
 
 bool
 build_pack_resource_status_request_aux(
-               uint8_t const* pLMN_Identity,
-        uint8_t const* eUTRANCellIdentifier,
+               uint8_t const** pLMN_Identities,
+        uint8_t const** eUTRANCellIdentifiers,
+        size_t nECGIs,
                Measurement_ID_t measurement_ID, Measurement_ID_t measurement_ID2,
                Registration_Request_t registration_Request /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
                uint32_t reportCharacteristics,
diff --git a/RSM/3rdparty/asn1codec/inc/resource_status_response_wrapper.h b/RSM/3rdparty/asn1codec/inc/resource_status_response_wrapper.h
new file mode 100644 (file)
index 0000000..e5d2ed9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef INC_RESOURCE_STATUS_RESPONSE_WRAPPER_H
+#define INC_RESOURCE_STATUS_RESPONSE_WRAPPER_H
+
+#include <UnsuccessfulOutcome.h>
+#include <SuccessfulOutcome.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_RESOURCE_STATUS_RESPONSE_WRAPPER_H */
index 3b07d94..0edd894 100644 (file)
@@ -42,8 +42,9 @@ static void assignEUTRANcellIdentifier (EUTRANCellIdentifier_t *eUTRANCellIdenti
 
 bool
 build_pack_resource_status_request(
-               uint8_t const* pLMN_Identity,
-               uint8_t const* eUTRANCellIdentifier,
+               uint8_t const** pLMN_Identities,
+               uint8_t const** eUTRANCellIdentifiers,
+               size_t nECGIs,
                Measurement_ID_t measurement_ID, Measurement_ID_t measurement_ID2,
                Registration_Request_t registration_Request /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
                uint32_t reportCharacteristics,
@@ -55,8 +56,9 @@ build_pack_resource_status_request(
 )
 {
        return build_pack_resource_status_request_aux(
-                       pLMN_Identity,
-            eUTRANCellIdentifier,
+                       pLMN_Identities,
+            eUTRANCellIdentifiers,
+            nECGIs,
                        measurement_ID, measurement_ID2,
                        registration_Request,
                        reportCharacteristics,
@@ -70,8 +72,9 @@ build_pack_resource_status_request(
 
 bool
 build_pack_resource_status_request_aux(
-               uint8_t const* pLMN_Identity,
-               uint8_t const* eUTRANCellIdentifier,
+               uint8_t const** pLMN_Identities,
+               uint8_t const** eUTRANCellIdentifiers,
+               size_t nECGIs,
                Measurement_ID_t measurement_ID, Measurement_ID_t measurement_ID2,
                Registration_Request_t registration_Request /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
                uint32_t reportCharacteristics,
@@ -155,15 +158,17 @@ build_pack_resource_status_request_aux(
     cellToReport_List_ie->criticality = Criticality_ignore;
     cellToReport_List_ie->value.present = ResourceStatusRequest_IEs__value_PR_CellToReport_List;
 
-    CellToReport_ItemIEs_t *item = calloc(1, sizeof(CellToReport_ItemIEs_t));
-    assert(item != 0);
-    ASN_SEQUENCE_ADD(&cellToReport_List_ie->value.choice.CellToReport_List, item);
+    for (size_t i = 0; i < nECGIs; i++){
+        CellToReport_ItemIEs_t *item = calloc(1, sizeof(CellToReport_ItemIEs_t));
+        assert(item != 0);
+        ASN_SEQUENCE_ADD(&cellToReport_List_ie->value.choice.CellToReport_List, item);
 
-    item->id = ProtocolIE_ID_id_CellToReport_Item;
-       item->criticality = Criticality_ignore;
-       item->value.present = CellToReport_ItemIEs__value_PR_CellToReport_Item;
-       assignPLMN_Identity(&item->value.choice.CellToReport_Item.cell_ID.pLMN_Identity, pLMN_Identity);
-       assignEUTRANcellIdentifier(&item->value.choice.CellToReport_Item.cell_ID.eUTRANcellIdentifier,eUTRANCellIdentifier);
+        item->id = ProtocolIE_ID_id_CellToReport_Item;
+        item->criticality = Criticality_ignore;
+        item->value.present = CellToReport_ItemIEs__value_PR_CellToReport_Item;
+        assignPLMN_Identity(&item->value.choice.CellToReport_Item.cell_ID.pLMN_Identity, pLMN_Identities[i]);
+        assignEUTRANcellIdentifier(&item->value.choice.CellToReport_Item.cell_ID.eUTRANcellIdentifier,eUTRANCellIdentifiers[i]);
+    }
 
        if (reportingPeriodicity >= 0){
                ResourceStatusRequest_IEs_t *reportingPeriodicity_ie = calloc(1, sizeof(ResourceStatusRequest_IEs_t));
index e4a7fe5..acef349 100644 (file)
     #include <resource_status_request_wrapper.h>
 
     void test_build_pack_resource_status_request();
+    void test_build_pack_resource_status_request_stop();
     void test_unpack(void);
 
     int
     main(int argc, char* argv[])
     {
        test_build_pack_resource_status_request();
+       test_build_pack_resource_status_request_stop();
         exit(0);
     }
 
@@ -52,12 +54,14 @@ or Third bits is set to 1,
         size_t packed_buf_size = 4096;
         unsigned char outBuf[packed_buf_size];
         char errorBuf[error_buf_size];
-        uint8_t pLMN_Identity[] = {0xa,0xb,0xc};
-        uint8_t eUTRANCellIdentifier[] = {0xab, 0xcd, 0x70, 0};
+        const uint8_t pLMN_Identity[] = {0xa,0xb,0xc};
+        const uint8_t eUTRANCellIdentifier[] = {0xab, 0xcd, 0x70, 0};
+        const uint8_t *pLMN_Identities[] = {pLMN_Identity};
+        const uint8_t *eUTRANCellIdentifiers[] = {eUTRANCellIdentifier};
         E2AP_PDU_t *pdu;
 
         bool result = build_pack_resource_status_request(
-                       pLMN_Identity, eUTRANCellIdentifier,
+                       pLMN_Identities, eUTRANCellIdentifiers, 1,
                        15 /*measurement_ID*/, 0  /*measurement_ID2*/,
                                Registration_Request_start /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
                        0xf0,
@@ -86,3 +90,44 @@ or Third bits is set to 1,
 
     }
 
+void test_build_pack_resource_status_request_stop(){
+        size_t error_buf_size = 8192;
+        size_t packed_buf_size = 4096;
+        unsigned char outBuf[packed_buf_size];
+        char errorBuf[error_buf_size];
+        const uint8_t pLMN_Identity[] = {0xa,0xb,0xc};
+        const uint8_t eUTRANCellIdentifier[] = {0xab, 0xcd, 0x70, 0};
+        const uint8_t *pLMN_Identities[] = {pLMN_Identity};
+        const uint8_t *eUTRANCellIdentifiers[] = {eUTRANCellIdentifier};
+        E2AP_PDU_t *pdu;
+
+        bool result = build_pack_resource_status_request(
+                       pLMN_Identities, eUTRANCellIdentifiers, 1,
+                       15 /*measurement_ID*/, 2  /*measurement_ID2*/,
+                               Registration_Request_stop /*Registration_Request_start,Registration_Request_stop,Registration_Request_partial_stop, Registration_Request_add*/,
+                       0,
+                               ReportingPeriodicity_one_thousand_ms /*ReportingPeriodicity_one_thousand_ms, ReportingPeriodicity_two_thousand_ms, ReportingPeriodicity_five_thousand_ms,ReportingPeriodicity_ten_thousand_ms*/,
+                               PartialSuccessIndicator_partial_success_allowed /*PartialSuccessIndicator_partial_success_allowed*/,
+                               ReportingPeriodicityRSRPMR_one_hundred_20_ms /*ReportingPeriodicityRSRPMR_one_hundred_20_ms, ReportingPeriodicityRSRPMR_two_hundred_40_ms, ReportingPeriodicityRSRPMR_four_hundred_80_ms,ReportingPeriodicityRSRPMR_six_hundred_40_ms*/,
+                               ReportingPeriodicityCSIR_ms5 /* ReportingPeriodicityCSIR_ms5, ReportingPeriodicityCSIR_ms10,ReportingPeriodicityCSIR_ms20,ReportingPeriodicityCSIR_ms40,ReportingPeriodicityCSIR_ms80*/,
+                       &packed_buf_size, outBuf, error_buf_size, errorBuf);
+
+        if (!result) {
+            printf("#%s failed. Packing error %s\n", __func__,errorBuf);
+            return;
+        }
+        printf("packed size:%lu\nPayload:\n", packed_buf_size);
+        for (size_t i = 0; i < packed_buf_size; ++i)
+            printf("%02x",outBuf[i]);
+        printf("\n");
+
+        pdu = calloc(1, sizeof(E2AP_PDU_t));
+        if (!unpack_pdu_aux(pdu, packed_buf_size, outBuf,error_buf_size, errorBuf,ATS_ALIGNED_BASIC_PER)){
+               printf("#%s failed. Unpacking error %s\n", __func__, errorBuf);
+        }
+        errorBuf[0] = 0;
+        asn1_pdu_printer(pdu, sizeof(errorBuf), errorBuf);
+        printf("#%s: %s\n", __func__, errorBuf);
+
+    }
+
index a2c55ee..e02f725 100644 (file)
 #   platform project (RICP).
 #
 
-FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:2-u16.04-nng as ubuntu
+FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:3-u16.04-nng as ubuntu
 
 WORKDIR /opt/RSM
 COPY . . 
 ENV PATH=$PATH:/usr/local/go/bin:/usr/lib/go-1.12/bin
 # Install RMr library and dev files
-RUN wget --content-disposition  https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_1.10.0_amd64.deb/download.deb
-RUN dpkg -i rmr_1.10.0_amd64.deb
-RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_1.10.0_amd64.deb/download.deb
-RUN dpkg -i rmr-dev_1.10.0_amd64.deb
+RUN wget --content-disposition  https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_1.13.0_amd64.deb/download.deb
+RUN dpkg -i rmr_1.13.0_amd64.deb
+RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_1.13.0_amd64.deb/download.deb
+RUN dpkg -i rmr-dev_1.13.0_amd64.deb
 
 
 RUN cd 3rdparty/asn1codec && make  
index 22eb9e6..17a4ed9 100644 (file)
@@ -23,23 +23,24 @@ package main
 import (
        "fmt"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
+       "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
        "os"
        "rsm/configuration"
        "rsm/controllers"
        "rsm/converters"
+       "rsm/e2pdus"
        "rsm/httpserver"
        "rsm/logger"
-       "rsm/managers"
        "rsm/managers/rmrmanagers"
+       "rsm/providers/httpmsghandlerprovider"
        "rsm/rmrcgo"
+       "rsm/rsmdb"
        "rsm/services"
        "rsm/services/rmrreceiver"
        "rsm/services/rmrsender"
        "strconv"
 )
 
-const MaxRnibPoolInstances = 4
-
 func main() {
        config, err := configuration.ParseConfiguration()
        if err != nil {
@@ -52,23 +53,29 @@ func main() {
                fmt.Printf("#app.main - failed to initialize logger, error: %s", err)
                os.Exit(1)
        }
-       reader.Init("e2Manager", MaxRnibPoolInstances)
+       db := sdlgo.NewDatabase()
+       e2mSdl := sdlgo.NewSdlInstance("e2Manager", db)
+       rsmSdl := sdlgo.NewSdlInstance("rsm", db)
+
+       defer e2mSdl.Close()
+       defer rsmSdl.Close()
+
        logger.Infof("#app.main - Configuration %s", config)
-       defer reader.Close()
-       rnibDataService := services.NewRnibDataService(logger, config, reader.GetRNibReader)
+       rnibDataService := services.NewRnibDataService(logger, config, reader.GetRNibReader(e2mSdl), rsmdb.GetRsmReader(rsmSdl), rsmdb.GetRsmWriter(rsmSdl))
        var msgImpl *rmrcgo.Context
        rmrMessenger := msgImpl.Init(config.Rmr.ReadyIntervalSec, "tcp:"+strconv.Itoa(config.Rmr.Port), config.Rmr.MaxMsgSize, 0, logger)
        rmrSender := rmrsender.NewRmrSender(logger, rmrMessenger)
 
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-       var rmrManager = rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,converters.NewX2apPduUnpacker(logger))
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       var rmrManager = rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        rmrReceiver := rmrreceiver.NewRmrReceiver(logger, rmrMessenger, rmrManager)
        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 5bc1a30..74306e7 100644 (file)
@@ -23,7 +23,6 @@ package configuration
 import (
        "fmt"
        "github.com/spf13/viper"
-       "rsm/enums"
 )
 
 type Configuration struct {
@@ -42,19 +41,6 @@ type Configuration struct {
                MaxRnibConnectionAttempts int
                RnibRetryIntervalMs       int
        }
-       ResourceStatusParams struct {
-               EnableResourceStatus         bool
-               PartialSuccessAllowed        bool
-               PrbPeriodic                  bool
-               TnlLoadIndPeriodic           bool
-               HwLoadIndPeriodic            bool
-               AbsStatusPeriodic            bool
-               RsrpMeasurementPeriodic      bool
-               CsiPeriodic                  bool
-               PeriodicityMs                enums.ReportingPeriodicity
-               PeriodicityRsrpMeasurementMs enums.ReportingPeriodicityRSRPMR
-               PeriodicityCsiMs             enums.ReportingPeriodicityCSIR
-       }
 }
 
 func ParseConfiguration() (*Configuration, error) {
@@ -81,9 +67,6 @@ func ParseConfiguration() (*Configuration, error) {
        if err := config.fillRnibConfig(viper.Sub("rnib")); err != nil {
                return nil, err
        }
-       if err := config.fillResourceStatusParamsConfig(viper.Sub("resourceStatusParams")); err != nil {
-               return nil, err
-       }
 
        return &config, nil
 }
@@ -123,69 +106,9 @@ func (c *Configuration) fillRnibConfig(rnibConfig *viper.Viper) error {
        return nil
 }
 
-func (c *Configuration) fillResourceStatusParamsConfig(chConfig *viper.Viper) error {
-       if chConfig == nil {
-               return fmt.Errorf("#configuration.fillResourceStatusParamsConfig - failed to fill resourceStatusParams configuration: The entry 'resourceStatusParams' not found\n")
-       }
-       c.ResourceStatusParams.EnableResourceStatus = chConfig.GetBool("enableResourceStatus")
-       c.ResourceStatusParams.PartialSuccessAllowed = chConfig.GetBool("partialSuccessAllowed")
-       c.ResourceStatusParams.PrbPeriodic = chConfig.GetBool("prbPeriodic")
-       c.ResourceStatusParams.TnlLoadIndPeriodic = chConfig.GetBool("tnlLoadIndPeriodic")
-       c.ResourceStatusParams.HwLoadIndPeriodic = chConfig.GetBool("hwLoadIndPeriodic")
-       c.ResourceStatusParams.AbsStatusPeriodic = chConfig.GetBool("absStatusPeriodic")
-       c.ResourceStatusParams.RsrpMeasurementPeriodic = chConfig.GetBool("rsrpMeasurementPeriodic")
-       c.ResourceStatusParams.CsiPeriodic = chConfig.GetBool("csiPeriodic")
-       if err := setPeriodicityMs(c, chConfig.GetInt("periodicityMs")); err != nil {
-               return err
-       }
-       if err := setPeriodicityRsrpMeasurementMs(c, chConfig.GetInt("periodicityRsrpMeasurementMs")); err != nil {
-               return err
-       }
-       if err := setPeriodicityCsiMs(c, chConfig.GetInt("periodicityCsiMs")); err != nil {
-               return err
-       }
-       return nil
-}
-
-func setPeriodicityMs(c *Configuration, periodicityMs int) error {
-       v, ok := enums.ReportingPeriodicityValues[periodicityMs]
-
-       if !ok {
-               return fmt.Errorf("Invalid configuration value supplied for PeriodicityMs. Received: %d. Should be one of: %v\n", periodicityMs, enums.GetReportingPeriodicityValuesAsKeys())
-       }
-
-       c.ResourceStatusParams.PeriodicityMs = v
-       return nil
-}
-
-func setPeriodicityRsrpMeasurementMs(c *Configuration, periodicityRsrpMeasurementMs int) error {
-       v, ok := enums.ReportingPeriodicityRsrPmrValues[periodicityRsrpMeasurementMs]
-
-       if !ok {
-               return fmt.Errorf("Invalid configuration value supplied for PeriodicityRsrpMeasurementMs. Received: %d. Should be one of: %v\n", periodicityRsrpMeasurementMs, enums.GetReportingPeriodicityRsrPmrValuesAsKeys())
-       }
-
-       c.ResourceStatusParams.PeriodicityRsrpMeasurementMs = v
-       return nil
-}
-
-func setPeriodicityCsiMs(c *Configuration, periodicityCsiMs int) error {
-       v, ok := enums.ReportingPeriodicityCsirValues[periodicityCsiMs]
-
-       if !ok {
-               return fmt.Errorf("Invalid configuration value supplied for PeriodicityCsiMs. Received: %d. Should be one of: %v\n", periodicityCsiMs, enums.GetReportingPeriodicityCsirValuesAsKeys())
-       }
-
-       c.ResourceStatusParams.PeriodicityCsiMs = v
-       return nil
-}
 
 func (c *Configuration) String() string {
-       return fmt.Sprintf("{logging.logLevel: %s, http.port: %d, rmr.port: %d, rmr.maxMsgSize: %d, rmr.readyIntervalSec: %d, rnib.maxRnibConnectionAttempts: %d, rnib.rnibRetryIntervalMs: %d, "+
-               "resourceStatusParams.enableResourceStatus: %t, resourceStatusParams.partialSuccessAllowed: %t, resourceStatusParams.prbPeriodic: %t, "+
-               "resourceStatusParams.tnlLoadIndPeriodic: %t, resourceStatusParams.hwLoadIndPeriodic: %t, resourceStatusParams.absStatusPeriodic: %t,"+
-               "resourceStatusParams.rsrpMeasurementPeriodic: %t, resourceStatusParams.csiPeriodic: %t, resourceStatusParams.periodicityMs: %s, "+
-               "resourceStatusParams.periodicityRsrpMeasurementMs: %s, resourceStatusParams.periodicityCsiMs: %s}",
+       return fmt.Sprintf("{logging.logLevel: %s, http.port: %d, rmr.port: %d, rmr.maxMsgSize: %d, rmr.readyIntervalSec: %d, rnib.maxRnibConnectionAttempts: %d, rnib.rnibRetryIntervalMs: %d, ",
                c.Logging.LogLevel,
                c.Http.Port,
                c.Rmr.Port,
@@ -193,17 +116,5 @@ func (c *Configuration) String() string {
                c.Rmr.ReadyIntervalSec,
                c.Rnib.MaxRnibConnectionAttempts,
                c.Rnib.RnibRetryIntervalMs,
-               c.ResourceStatusParams.EnableResourceStatus,
-               c.ResourceStatusParams.PartialSuccessAllowed,
-               c.ResourceStatusParams.PrbPeriodic,
-               c.ResourceStatusParams.TnlLoadIndPeriodic,
-               c.ResourceStatusParams.HwLoadIndPeriodic,
-               c.ResourceStatusParams.AbsStatusPeriodic,
-               c.ResourceStatusParams.RsrpMeasurementPeriodic,
-               c.ResourceStatusParams.CsiPeriodic,
-
-               c.ResourceStatusParams.PeriodicityMs,
-               c.ResourceStatusParams.PeriodicityRsrpMeasurementMs,
-               c.ResourceStatusParams.PeriodicityCsiMs,
        )
 }
index 7c21f36..1ac4204 100644 (file)
@@ -40,19 +40,6 @@ func TestParseConfigurationSuccess(t *testing.T) {
 
        assert.Equal(t, 3, config.Rnib.MaxRnibConnectionAttempts)
        assert.Equal(t, 10, config.Rnib.RnibRetryIntervalMs)
-
-       assert.Equal(t, true, config.ResourceStatusParams.EnableResourceStatus)
-       assert.Equal(t, true, config.ResourceStatusParams.PrbPeriodic)
-       assert.Equal(t, true, config.ResourceStatusParams.TnlLoadIndPeriodic)
-       assert.Equal(t, true, config.ResourceStatusParams.HwLoadIndPeriodic)
-       assert.Equal(t, true, config.ResourceStatusParams.AbsStatusPeriodic)
-       assert.Equal(t, true, config.ResourceStatusParams.RsrpMeasurementPeriodic)
-       assert.Equal(t, true, config.ResourceStatusParams.CsiPeriodic)
-
-       /*assert.Equal(t, 1, config.ResourceStatusParams.PeriodicityMs)
-       assert.Equal(t, 120, config.ResourceStatusParams.PeriodicityRsrpMeasurementMs)
-       assert.Equal(t, 5, config.ResourceStatusParams.PeriodicityCsiMs)*/
-
 }
 
 func TestParseConfigurationFileNotFoundFailure(t *testing.T) {
@@ -75,10 +62,9 @@ func TestParseConfigurationFileNotFoundFailure(t *testing.T) {
 
 func TestRmrConfigNotFoundFailure(t *testing.T) {
        yamlMap := map[string]interface{}{
-               "logging":         map[string]interface{}{"logLevel": "info"},
-               "http":            map[string]interface{}{"port": 631},
-               "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityCsiMs": 5},
-               "rnib":            map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
+               "logging":              map[string]interface{}{"logLevel": "info"},
+               "http":                 map[string]interface{}{"port": 631},
+               "rnib":                 map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
        }
        cleanUp := prepareTempConfigForTest(t, yamlMap)
        defer cleanUp()
@@ -89,10 +75,10 @@ func TestRmrConfigNotFoundFailure(t *testing.T) {
 
 func TestLoggingConfigNotFoundFailure(t *testing.T) {
        yamlMap := map[string]interface{}{
-               "rmr":             map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "http":            map[string]interface{}{"port": 631},
+               "rmr":                  map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
+               "http":                 map[string]interface{}{"port": 631},
                "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityCsiMs": 5},
-               "rnib":            map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
+               "rnib":                 map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
        }
        cleanUp := prepareTempConfigForTest(t, yamlMap)
        defer cleanUp()
@@ -103,10 +89,10 @@ func TestLoggingConfigNotFoundFailure(t *testing.T) {
 
 func TestHttpConfigNotFoundFailure(t *testing.T) {
        yamlMap := map[string]interface{}{
-               "rmr":             map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging":         map[string]interface{}{"logLevel": "info"},
+               "rmr":                  map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
+               "logging":              map[string]interface{}{"logLevel": "info"},
                "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityCsiMs": 5},
-               "rnib":            map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
+               "rnib":                 map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
        }
        cleanUp := prepareTempConfigForTest(t, yamlMap)
        defer cleanUp()
@@ -117,10 +103,9 @@ func TestHttpConfigNotFoundFailure(t *testing.T) {
 
 func TestRnibConfigNotFoundFailure(t *testing.T) {
        yamlMap := map[string]interface{}{
-               "rmr":             map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging":         map[string]interface{}{"logLevel": "info"},
-               "http":            map[string]interface{}{"port": 631},
-               "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityCsiMs": 5},
+               "rmr":                  map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
+               "logging":              map[string]interface{}{"logLevel": "info"},
+               "http":                 map[string]interface{}{"port": 631},
        }
        cleanUp := prepareTempConfigForTest(t, yamlMap)
        defer cleanUp()
@@ -129,69 +114,6 @@ func TestRnibConfigNotFoundFailure(t *testing.T) {
        assert.EqualError(t, cErr, "#configuration.fillRnibConfig - failed to fill RNib configuration: The entry 'rnib' not found\n")
 }
 
-func TestResourceStatusParamsConfigNotFoundFailure(t *testing.T) {
-
-       yamlMap := map[string]interface{}{
-               "rmr":     map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging": map[string]interface{}{"logLevel": "info"},
-               "http":    map[string]interface{}{"port": 631},
-               "rnib":    map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
-       }
-       cleanUp := prepareTempConfigForTest(t, yamlMap)
-       defer cleanUp()
-
-       _, cErr := ParseConfiguration()
-       assert.EqualError(t, cErr, "#configuration.fillResourceStatusParamsConfig - failed to fill resourceStatusParams configuration: The entry 'resourceStatusParams' not found\n")
-}
-
-func TestCharacteristicsConfigInvalidPeriodicityMs(t *testing.T) {
-
-       yamlMap := map[string]interface{}{
-               "rmr":     map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging": map[string]interface{}{"logLevel": "info"},
-               "http":    map[string]interface{}{"port": 631},
-               "rnib":    map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
-               "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityMs": 50, "periodicityRsrpMeasurementMs": 480, "periodicityCsiMs": 20},
-       }
-       cleanUp := prepareTempConfigForTest(t, yamlMap)
-       defer cleanUp()
-
-       _, cErr := ParseConfiguration()
-       assert.Error(t, cErr)
-}
-
-func TestResourceStatusParamsConfigInvalidPeriodicityRsrpMeasurementMs(t *testing.T) {
-
-       yamlMap := map[string]interface{}{
-               "rmr":     map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging": map[string]interface{}{"logLevel": "info"},
-               "http":    map[string]interface{}{"port": 631},
-               "rnib":    map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
-               "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityMs": 1000, "periodicityRsrpMeasurementMs": 50, "periodicityCsiMs": 20},
-       }
-       cleanUp := prepareTempConfigForTest(t, yamlMap)
-       defer cleanUp()
-
-       _, cErr := ParseConfiguration()
-       assert.Error(t, cErr)
-}
-
-func TestResourceStatusParamsConfigInvalidPeriodicityCsiMs(t *testing.T) {
-
-       yamlMap := map[string]interface{}{
-               "rmr":     map[string]interface{}{"port": 6942, "maxMsgSize": 4096},
-               "logging": map[string]interface{}{"logLevel": "info"},
-               "http":    map[string]interface{}{"port": 631},
-               "rnib":    map[string]interface{}{"maxRnibConnectionAttempts": 3, "rnibRetryIntervalMs": 10},
-               "resourceStatusParams": map[string]interface{}{"enableResourceStatus": true, "periodicityMs": 1000, "periodicityRsrpMeasurementMs": 480, "periodicityCsiMs": 50},
-       }
-       cleanUp := prepareTempConfigForTest(t, yamlMap)
-       defer cleanUp()
-
-       _, cErr := ParseConfiguration()
-       assert.Error(t, cErr)
-}
-
 func TestConfigurationString(t *testing.T) {
        config, err := ParseConfiguration()
        if err != nil {
@@ -203,7 +125,6 @@ func TestConfigurationString(t *testing.T) {
        assert.Contains(t, str, "http")
        assert.Contains(t, str, "rmr")
        assert.Contains(t, str, "rnib")
-       assert.Contains(t, str, "resourceStatusParams")
 }
 
 func prepareTempConfigForTest(t *testing.T, yamlMap map[string]interface{}) func() {
index abb1c65..f572821 100644 (file)
@@ -20,9 +20,6 @@
 
 package controllers
 
-type IController interface {
-}
-/*
 import (
        "encoding/json"
        "io"
@@ -41,6 +38,7 @@ const (
 )
 
 type IController interface {
+       ResourceStatus(writer http.ResponseWriter, r *http.Request)
 }
 
 type Controller struct {
@@ -55,6 +53,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))
@@ -93,29 +103,15 @@ func (c *Controller) handleRequest(writer http.ResponseWriter, header *http.Head
                return
        }
 
-       response, err := (*handler).Handle(request)
+       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()
-
-       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 {
@@ -159,6 +155,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}
@@ -181,11 +181,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
+}
\ No newline at end of file
index cc27b3c..db5462e 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{}
@@ -62,9 +154,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()
@@ -75,10 +167,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")
@@ -86,8 +178,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)
@@ -97,10 +189,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)
@@ -133,5 +225,8 @@ func TestHandleErrorResponse(t *testing.T) {
        writer = httptest.NewRecorder()
        controller.handleErrorResponse(fmt.Errorf("ErrorError"), writer)
        assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
-}
-*/
\ No newline at end of file
+
+       writer = httptest.NewRecorder()
+       controller.handleErrorResponse(rsmerrors.NewRsmError(2), writer)
+       assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode)
+}
\ No newline at end of file
index b79271f..9e917ff 100644 (file)
@@ -24,7 +24,6 @@ import (
        "fmt"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
-       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
        "github.com/stretchr/testify/assert"
        "net"
        "net/http"
@@ -45,12 +44,12 @@ func setupRootControllerTest(t *testing.T) (services.RNibDataService, *mocks.Rni
        if err != nil {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
-       readerMock := &mocks.RnibReaderMock{}
-       rnibReaderProvider := func() reader.RNibReader {
-               return readerMock
-       }
-       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider)
-       return rnibDataService, readerMock
+       rnibReaderMock := &mocks.RnibReaderMock{}
+       rsmReaderMock := &mocks.RsmReaderMock{}
+       rsmWriterMock := &mocks.RsmWriterMock{}
+
+       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderMock, rsmReaderMock, rsmWriterMock)
+       return rnibDataService, rnibReaderMock
 }
 
 func TestNewRequestController(t *testing.T) {
diff --git a/RSM/converters/resource_status_failure_unpacker.go b/RSM/converters/resource_status_failure_unpacker.go
new file mode 100644 (file)
index 0000000..d76f5f8
--- /dev/null
@@ -0,0 +1,125 @@
+//
+// 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 converters
+
+// #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 <resource_status_response_wrapper.h>
+import "C"
+import (
+       "fmt"
+       "rsm/models"
+       "unsafe"
+)
+
+type ResourceStatusFailureConverter struct {
+       X2apPduUnpacker
+}
+
+func NewResourceStatusFailureConverter(unpacker X2apPduUnpacker) ResourceStatusFailureConverter {
+       return ResourceStatusFailureConverter{unpacker}
+}
+
+func convertCompleteFailureCauseInformation(completeFailureCauseInformation_List *C.CompleteFailureCauseInformation_List_t) ([]*models.MeasurementInitiationResult, error) {
+       var measurementInitiationResults []*models.MeasurementInitiationResult
+
+       count := int(completeFailureCauseInformation_List.list.count)
+       if count < 1 || count > maxCellineNB {
+               return nil, fmt.Errorf("invalid number of complete failure cause information elements, %d", count)
+       }
+       completeFailureCauseInformation_ItemIEs_slice := (*[1 << 30]*C.CompleteFailureCauseInformation_ItemIEs_t)(unsafe.Pointer(completeFailureCauseInformation_List.list.array))[:count:count]
+       for _, itemIE := range completeFailureCauseInformation_ItemIEs_slice {
+
+               switch itemIE.value.present {
+               case C.CompleteFailureCauseInformation_ItemIEs__value_PR_CompleteFailureCauseInformation_Item:
+                       item := (*C.CompleteFailureCauseInformation_Item_t)(unsafe.Pointer(&itemIE.value.choice[0]))
+                       measurementInitiationResult := models.MeasurementInitiationResult{CellId: buildCellId(item.cell_ID)}
+                       if err:=convertMeasurementFailureCauses(&item.measurementFailureCause_List, &measurementInitiationResult); err != nil {
+                               return nil, err
+                       }
+                       measurementInitiationResults = append(measurementInitiationResults, &measurementInitiationResult)
+               }
+       }
+
+       return measurementInitiationResults, nil
+}
+
+func convertResourceFailureIEs(resourceStatusFailure *C.ResourceStatusFailure_t, response *models.ResourceStatusResponse) error {
+       count := int(resourceStatusFailure.protocolIEs.list.count)
+       resourceStatusFailure_IEs_slice := (*[1 << 30]*C.ResourceStatusFailure_IEs_t)(unsafe.Pointer(resourceStatusFailure.protocolIEs.list.array))[:count:count]
+       for _, resourceStatusFailure_IEs := range resourceStatusFailure_IEs_slice {
+               switch resourceStatusFailure_IEs.value.present {
+               case C.ResourceStatusFailure_IEs__value_PR_Measurement_ID:
+                       measurement_ID := (*C.Measurement_ID_t)(unsafe.Pointer(&resourceStatusFailure_IEs.value.choice[0]))
+                       if resourceStatusFailure_IEs.id == C.ProtocolIE_ID_id_ENB1_Measurement_ID {
+                               response.ENB1_Measurement_ID = int64(*measurement_ID)
+                       }
+                       if resourceStatusFailure_IEs.id == C.ProtocolIE_ID_id_ENB2_Measurement_ID {
+                               response.ENB2_Measurement_ID = int64(*measurement_ID)
+                       }
+               case C.ResourceStatusFailure_IEs__value_PR_CriticalityDiagnostics:
+                       /*ignored*/
+               case C.ResourceStatusFailure_IEs__value_PR_Cause:
+                       /*ignored*/
+               case C.ResourceStatusFailure_IEs__value_PR_CompleteFailureCauseInformation_List:
+                       measurementInitiationResults, err := convertCompleteFailureCauseInformation((*C.CompleteFailureCauseInformation_List_t)(unsafe.Pointer(&resourceStatusFailure_IEs.value.choice[0])))
+                       if err != nil {
+                               return err
+                       }
+                       response.MeasurementInitiationResults = measurementInitiationResults
+               }
+       }
+       return nil
+}
+
+func convertResourceStatusFailure(pdu *C.E2AP_PDU_t) (*models.ResourceStatusResponse, error) {
+       response := models.ResourceStatusResponse{}
+
+       if pdu.present != C.E2AP_PDU_PR_unsuccessfulOutcome {
+               return &response, fmt.Errorf("unexpected PDU, %d", int(pdu.present))
+       }
+
+       //dereference a union of pointers (C union is represented as a byte array with the size of the largest member)
+       unsuccessfulOutcome := *(**C.UnsuccessfulOutcome_t)(unsafe.Pointer(&pdu.choice[0]))
+       if unsuccessfulOutcome == nil || unsuccessfulOutcome.value.present != C.UnsuccessfulOutcome__value_PR_ResourceStatusFailure {
+               return &response, fmt.Errorf("unexpected PDU - not a resource status failure")
+       }
+
+       resourceStatusFailure := (*C.ResourceStatusFailure_t)(unsafe.Pointer(&unsuccessfulOutcome.value.choice[0]))
+       if resourceStatusFailure.protocolIEs.list.count == 0 {
+               return &response, fmt.Errorf("unexpected PDU - no protocolIEs found")
+       }
+
+       if err := convertResourceFailureIEs(resourceStatusFailure, &response); err != nil {
+               return &response, err
+       }
+
+       return &response, nil
+}
+
+// Convert pdu to public ResourceStatusResponse
+func (r ResourceStatusFailureConverter) Convert(packedBuf []byte) (*models.ResourceStatusResponse, error) {
+       pdu, err := r.UnpackX2apPdu(packedBuf)
+       if err != nil {
+               return nil, err
+       }
+
+       defer C.delete_pdu(pdu)
+       return convertResourceStatusFailure(pdu)
+}
diff --git a/RSM/converters/resource_status_failure_unpacker_test.go b/RSM/converters/resource_status_failure_unpacker_test.go
new file mode 100644 (file)
index 0000000..fbbdf3b
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ *
+ *   Copyright (c) 2019 AT&T Intellectual Property.
+ *
+ *   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 converters
+
+import (
+       "fmt"
+       "rsm/e2pdus"
+       "rsm/logger"
+       "strings"
+       "testing"
+)
+
+/*
+ * Unpack a response returned from RAN.
+ * Verify it matches the want pdu.
+ */
+
+func TestResourceStatusFailureConverter(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.DebugLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsFailureConverter := NewResourceStatusFailureConverter(unpacker)
+
+       var testCases = []struct {
+               response  string
+               packedPdu string
+       }{
+               {
+                       response: "ENB1_Measurement_ID: 15, ENB2_Measurement_ID: 13, MeasurementInitiationResults:[ CellId: 02f829:0007ab50, MeasurementFailureCauses: [ MeasurementFailedReportCharacteristics: 00000007  ]  ]",
+                       /*
+                                       UnsuccessfulOutcome ::= {
+                                   procedureCode: 9
+                                   criticality: 0 (reject)
+                                   value: ResourceStatusFailure ::= {
+                                       protocolIEs: ProtocolIE-Container ::= {
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 39
+                                               criticality: 0 (reject)
+                                               value: 15
+                                           }
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 40
+                                               criticality: 0 (reject)
+                                               value: 13
+                                           }
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 5
+                                               criticality: 1 (ignore)
+                                               value: 1 (hardware-failure)
+                                           }
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 68
+                                               criticality: 1 (ignore)
+                                               value: CompleteFailureCauseInformation-List ::= {
+                                                   ProtocolIE-Single-Container ::= {
+                                                       id: 69
+                                                       criticality: 1 (ignore)
+                                                       value: CompleteFailureCauseInformation-Item ::= {
+                                                           cell-ID: ECGI ::= {
+                                                               pLMN-Identity: 02 F8 29
+                                                               eUTRANcellIdentifier: 00 07 AB 50 (4 bits unused)
+                                                           }
+                                                           measurementFailureCause-List: MeasurementFailureCause-List ::= {
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 00 00 00 07
+                                                                       cause: 0 (transfer-syntax-error)
+                                                                   }
+                                                               }
+                                                           }
+                                                       }
+                                                   }
+                                               }
+                                           }
+                                       }
+                                   }
+                               }*/
+
+                       packedPdu: "400900320000040027000300000e0028000300000c00054001620044401800004540130002f8290007ab500000434006000000000740",
+               },
+               {
+                       response: "ENB1_Measurement_ID: 1, ENB2_Measurement_ID: 74, MeasurementInitiationResults:[  ]",
+                       /*
+                               UnsuccessfulOutcome ::= {
+                                   procedureCode: 9
+                                   criticality: 0 (reject)
+                                   value: ResourceStatusFailure ::= {
+                                       protocolIEs: ProtocolIE-Container ::= {
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 39
+                                               criticality: 0 (reject)
+                                               value: 1
+                                           }
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 40
+                                               criticality: 0 (reject)
+                                               value: 74
+                                           }
+                                           ResourceStatusFailure-IEs ::= {
+                                               id: 5
+                                               criticality: 1 (ignore)
+                                               value: 21 (unspecified)
+                                           }
+                                       }
+                                   }
+                               }
+                       */
+                       packedPdu: "400900170000030027000300000000280003000049000540020a80",
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.packedPdu, func(t *testing.T) {
+                       var payload []byte
+
+                       _, err := fmt.Sscanf(tc.packedPdu, "%x", &payload)
+                       if err != nil {
+                               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+                       }
+
+                       response, err := rsFailureConverter.Convert(payload)
+                       if err != nil {
+                               t.Errorf("want: success, got: unpack failed. Error: %v\n", err)
+                       }
+
+                       got := response.String()
+                       if len(tc.response) != len(got) {
+                               t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", tc.response, response)
+                       }
+                       if strings.Compare(tc.response, got) != 0 {
+                               t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", tc.response, got)
+                       }
+               })
+       }
+}
+
+/*unpacking error*/
+
+func TestResourceStatusFailureConverterError(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsFailureConverter := NewResourceStatusFailureConverter(unpacker)
+       wantError := "unpacking error: #src/asn1codec_utils.c.unpack_pdu_aux - Failed to decode E2AP-PDU (consumed 0), error = 0 Success"
+       //--------------------2006002a
+       inputPayloadAsStr := "2006002b000002001500080002f82900007a8000140017000000630002f8290007ab50102002f829000001000133"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsFailureConverter.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusFailureConverterPduOfSuccess(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsFailureConverter := NewResourceStatusFailureConverter(unpacker)
+       wantError := "unexpected PDU, 2"
+       inputPayloadAsStr := "200900220000030027000300000e0028000300000c0041400d00004240080002f8290007ab50"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsFailureConverter.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusFailureConverterWrongPdu(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsFailureConverter := NewResourceStatusFailureConverter(unpacker)
+       wantError := "unexpected PDU - not a resource status failure"
+       inputPayloadAsStr := "4006001a0000030005400200000016400100001140087821a00000008040"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsFailureConverter.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
diff --git a/RSM/converters/resource_status_response_unpacker.go b/RSM/converters/resource_status_response_unpacker.go
new file mode 100644 (file)
index 0000000..b50251b
--- /dev/null
@@ -0,0 +1,166 @@
+//
+// 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 converters
+
+// #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 <resource_status_response_wrapper.h>
+import "C"
+import (
+       "fmt"
+       "rsm/models"
+       "unsafe"
+)
+
+const (
+       maxCellineNB         = 256
+       maxFailedMeasObjects = 32
+)
+
+type IResourceStatusResponseConverter interface {
+       Convert(packedBuf []byte) (*models.ResourceStatusResponse, error)
+       UnpackX2apPduAsString(packedBuf []byte, maxMessageBufferSize int) (string, error)
+}
+
+type ResourceStatusResponseConverter struct {
+       X2apPduUnpacker
+}
+
+func NewResourceStatusResponseConverter(unpacker X2apPduUnpacker) ResourceStatusResponseConverter {
+       return ResourceStatusResponseConverter{unpacker}
+}
+
+func buildCellId(cellId C.ECGI_t) string {
+       plmnId := C.GoBytes(unsafe.Pointer(cellId.pLMN_Identity.buf), C.int(cellId.pLMN_Identity.size))
+       eutranCellIdentifier := C.GoBytes(unsafe.Pointer(cellId.eUTRANcellIdentifier.buf), C.int(cellId.eUTRANcellIdentifier.size))
+       return fmt.Sprintf("%x:%x", plmnId, eutranCellIdentifier)
+}
+
+func convertMeasurementFailureCauses(measurementFailureCause_List *C.MeasurementFailureCause_List_t, measurementInitiationResult *models.MeasurementInitiationResult) error {
+       var MeasurementFailureCauses []*models.MeasurementFailureCause
+
+       count := int(measurementFailureCause_List.list.count)
+       if count < 1 || count > maxFailedMeasObjects {
+               return fmt.Errorf("invalid number of failure cause elements, %d", int(count))
+       }
+
+       measurementFailureCause_ItemIEs_slice := (*[1 << 30]*C.MeasurementFailureCause_ItemIEs_t)(unsafe.Pointer(measurementFailureCause_List.list.array))[:count:count]
+       for _, itemIE := range measurementFailureCause_ItemIEs_slice {
+               switch itemIE.value.present {
+               case C.MeasurementFailureCause_ItemIEs__value_PR_MeasurementFailureCause_Item:
+                       item := (*C.MeasurementFailureCause_Item_t)(unsafe.Pointer(&itemIE.value.choice[0]))
+                       measurementFailedReportCharacteristics := C.GoBytes(unsafe.Pointer(item.measurementFailedReportCharacteristics.buf), C.int(item.measurementFailedReportCharacteristics.size))
+                       measurementFailureCause := models.MeasurementFailureCause{MeasurementFailedReportCharacteristics: measurementFailedReportCharacteristics}
+                       MeasurementFailureCauses = append(MeasurementFailureCauses, &measurementFailureCause)
+                       /*Cause ignored - only need to know that the request failed and, possibly, which report characteristics failed*/
+               }
+               measurementInitiationResult.MeasurementFailureCauses = MeasurementFailureCauses
+       }
+
+       return nil
+}
+
+func convertMeasurementInitiationResult(measurementInitiationResult_List *C.MeasurementInitiationResult_List_t) ([]*models.MeasurementInitiationResult, error) {
+       var measurementInitiationResults []*models.MeasurementInitiationResult
+
+       count := int(measurementInitiationResult_List.list.count)
+       if count < 1 || count > maxCellineNB {
+               return nil, fmt.Errorf("invalid number of measurement initiation result elements, %d", count)
+       }
+       measurementInitiationResult_ItemIEs_slice := (*[1 << 30]*C.MeasurementInitiationResult_ItemIEs_t)(unsafe.Pointer(measurementInitiationResult_List.list.array))[:count:count]
+       for _, itemIE := range measurementInitiationResult_ItemIEs_slice {
+               switch itemIE.value.present {
+               case C.MeasurementInitiationResult_ItemIEs__value_PR_MeasurementInitiationResult_Item:
+                       item := (*C.MeasurementInitiationResult_Item_t)(unsafe.Pointer(&itemIE.value.choice[0]))
+                       measurementInitiationResult := models.MeasurementInitiationResult{CellId: buildCellId(item.cell_ID)}
+                       if item.measurementFailureCause_List != nil {
+                               if err:= convertMeasurementFailureCauses(item.measurementFailureCause_List, &measurementInitiationResult); err != nil {
+                                       return nil, err
+                               }
+                       }
+                       measurementInitiationResults = append(measurementInitiationResults, &measurementInitiationResult)
+               }
+
+       }
+
+       return measurementInitiationResults, nil
+}
+
+func convertResourceStatusIEs(resourceStatusResponse *C.ResourceStatusResponse_t, response *models.ResourceStatusResponse) error {
+       count := int(resourceStatusResponse.protocolIEs.list.count)
+       resourceStatusResponse_IEs_slice := (*[1 << 30]*C.ResourceStatusResponse_IEs_t)(unsafe.Pointer(resourceStatusResponse.protocolIEs.list.array))[:count:count]
+       for _, resourceStatusResponse_IEs := range resourceStatusResponse_IEs_slice {
+               switch resourceStatusResponse_IEs.value.present {
+               case C.ResourceStatusResponse_IEs__value_PR_Measurement_ID:
+                       measurement_ID := (*C.Measurement_ID_t)(unsafe.Pointer(&resourceStatusResponse_IEs.value.choice[0]))
+                       if resourceStatusResponse_IEs.id == C.ProtocolIE_ID_id_ENB1_Measurement_ID {
+                               response.ENB1_Measurement_ID = int64(*measurement_ID)
+                       }
+                       if resourceStatusResponse_IEs.id == C.ProtocolIE_ID_id_ENB2_Measurement_ID {
+                               response.ENB2_Measurement_ID = int64(*measurement_ID)
+                       }
+               case C.ResourceStatusResponse_IEs__value_PR_CriticalityDiagnostics:
+                       /*ignored*/
+
+               case C.ResourceStatusResponse_IEs__value_PR_MeasurementInitiationResult_List:
+                       measurementInitiationResults, err := convertMeasurementInitiationResult((*C.MeasurementInitiationResult_List_t)(unsafe.Pointer(&resourceStatusResponse_IEs.value.choice[0])))
+                       if err != nil {
+                               return err
+                       }
+                       response.MeasurementInitiationResults = measurementInitiationResults
+               }
+       }
+       return nil
+}
+
+func convertResourceStatusResponse(pdu *C.E2AP_PDU_t) (*models.ResourceStatusResponse, error) {
+       response := models.ResourceStatusResponse{}
+
+       if pdu.present != C.E2AP_PDU_PR_successfulOutcome {
+               return &response, fmt.Errorf("unexpected PDU, %d", int(pdu.present))
+       }
+
+       //dereference a union of pointers (C union is represented as a byte array with the size of the largest member)
+       successfulOutcome := *(**C.SuccessfulOutcome_t)(unsafe.Pointer(&pdu.choice[0]))
+       if successfulOutcome == nil || successfulOutcome.value.present != C.SuccessfulOutcome__value_PR_ResourceStatusResponse {
+               return &response, fmt.Errorf("unexpected PDU - not a resource status response")
+       }
+
+       resourceStatusResponse := (*C.ResourceStatusResponse_t)(unsafe.Pointer(&successfulOutcome.value.choice[0]))
+       if resourceStatusResponse.protocolIEs.list.count == 0 {
+               return &response, fmt.Errorf("unexpected PDU - no protocolIEs found")
+       }
+
+       if err := convertResourceStatusIEs(resourceStatusResponse, &response); err != nil {
+               return &response, err
+       }
+
+       return &response, nil
+}
+
+// Convert pdu to public ResourceStatusResponse
+func (r ResourceStatusResponseConverter) Convert(packedBuf []byte) (*models.ResourceStatusResponse, error) {
+       pdu, err := r.UnpackX2apPdu(packedBuf)
+       if err != nil {
+               return nil, err
+       }
+
+       defer C.delete_pdu(pdu)
+       return convertResourceStatusResponse(pdu)
+}
diff --git a/RSM/converters/resource_status_response_unpacker_test.go b/RSM/converters/resource_status_response_unpacker_test.go
new file mode 100644 (file)
index 0000000..114afd4
--- /dev/null
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ *
+ *   Copyright (c) 2019 AT&T Intellectual Property.
+ *
+ *   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 converters
+
+import (
+       "fmt"
+       "rsm/e2pdus"
+       "rsm/logger"
+       "strings"
+       "testing"
+)
+
+/*
+ * Unpack a response returned from RAN.
+ * Verify it matches the want pdu.
+ */
+
+func TestResourceStatusResponseConverter(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.DebugLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsConverters := NewResourceStatusResponseConverter(unpacker)
+
+       var testCases = []struct {
+               response  string
+               packedPdu string
+       }{
+               {
+                       response: "ENB1_Measurement_ID: 15, ENB2_Measurement_ID: 13, MeasurementInitiationResults:[ CellId: 02f829:0007ab50, MeasurementFailureCauses: [  ]  ]",
+                       /*
+                               SuccessfulOutcome ::= {
+                                       procedureCode: 9
+                                       criticality: 0 (reject)
+                                       value: ResourceStatusResponse ::= {
+                                               protocolIEs: ProtocolIE-Container ::= {
+                                                       ResourceStatusResponse-IEs ::= {
+                                                               id: 39
+                                                               criticality: 0 (reject)
+                                                               value: 15
+                                                       }
+                                                       ResourceStatusResponse-IEs ::= {
+                                                               id: 40
+                                                               criticality: 0 (reject)
+                                                               value: 13
+                                                       }
+                                                       ResourceStatusResponse-IEs ::= {
+                                                               id: 65
+                                                               criticality: 1 (ignore)
+                                                               value: MeasurementInitiationResult-List ::= {
+                                                                       ProtocolIE-Single-Container ::= {
+                                                                               id: 66
+                                                                               criticality: 1 (ignore)
+                                                                               value: MeasurementInitiationResult-Item ::= {
+                                                                                       cell-ID: ECGI ::= {
+                                                                                               pLMN-Identity: 02 F8 29
+                                                                                               eUTRANcellIdentifier: 00 07 AB 50 (4 bits unused)
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       */
+
+                       packedPdu: "200900220000030027000300000e0028000300000c0041400d00004240080002f8290007ab50",
+               },
+               {response: "ENB1_Measurement_ID: 1, ENB2_Measurement_ID: 75, MeasurementInitiationResults:[ CellId: 133023:02b030a0, MeasurementFailureCauses: [ MeasurementFailedReportCharacteristics: 02000000 MeasurementFailedReportCharacteristics: 04000000 MeasurementFailedReportCharacteristics: 08000000 MeasurementFailedReportCharacteristics: 20000000 MeasurementFailedReportCharacteristics: 40000000 MeasurementFailedReportCharacteristics: 80000000  ]  ]",
+                       /*
+                                SuccessfulOutcome ::= {
+                                   procedureCode: 9
+                                   criticality: 0 (reject)
+                                   value: ResourceStatusResponse ::= {
+                                       protocolIEs: ProtocolIE-Container ::= {
+                                           ResourceStatusResponse-IEs ::= {
+                                               id: 39
+                                               criticality: 0 (reject)
+                                               value: 1
+                                           }
+                                           ResourceStatusResponse-IEs ::= {
+                                               id: 40
+                                               criticality: 0 (reject)
+                                               value: 75
+                                           }
+                                           ResourceStatusResponse-IEs ::= {
+                                               id: 65
+                                               criticality: 1 (ignore)
+                                               value: MeasurementInitiationResult-List ::= {
+                                                   ProtocolIE-Single-Container ::= {
+                                                       id: 66
+                                                       criticality: 1 (ignore)
+                                                       value: MeasurementInitiationResult-Item ::= {
+                                                           cell-ID: ECGI ::= {
+                                                               pLMN-Identity: 13 30 23
+                                                               eUTRANcellIdentifier: 02 B0 30 A0 (4 bits unused)
+                                                           }
+                                                           measurementFailureCause-List: MeasurementFailureCause-List ::= {
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 02 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 04 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 08 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 20 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 40 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                               ProtocolIE-Single-Container ::= {
+                                                                   id: 67
+                                                                   criticality: 1 (ignore)
+                                                                   value: MeasurementFailureCause-Item ::= {
+                                                                       measurementFailedReportCharacteristics: 80 00 00 00
+                                                                       cause: 20 (measurement-temporarily-not-available)
+                                                                   }
+                                                               }
+                                                           }
+                                                       }
+                                                   }
+                                               }
+                                           }
+                                       }
+                                   }
+                               }
+                       */
+                       packedPdu: "20090065000003002700030000000028000300004a00414050000042404b4013302302b030a2800043400700020000000a000043400700040000000a000043400700080000000a000043400700200000000a000043400700400000000a000043400700800000000a00"},
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.packedPdu, func(t *testing.T) {
+                       var payload []byte
+
+                       _, err := fmt.Sscanf(tc.packedPdu, "%x", &payload)
+                       if err != nil {
+                               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+                       }
+
+                       response, err := rsConverters.Convert(payload)
+                       if err != nil {
+                               t.Errorf("want: success, got: unpack failed. Error: %v\n", err)
+                       }
+
+                       got := response.String()
+                       if len(tc.response) != len(got) {
+                               t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", tc.response, response)
+                       }
+                       if strings.Compare(tc.response, got) != 0 {
+                               t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", tc.response, got)
+                       }
+               })
+       }
+}
+
+/*unpacking error*/
+
+func TestResourceStatusResponseConverterError(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsConverters := NewResourceStatusResponseConverter(unpacker)
+
+       wantError := "unpacking error: #src/asn1codec_utils.c.unpack_pdu_aux - Failed to decode E2AP-PDU (consumed 0), error = 0 Success"
+       //--------------------2006002a
+       inputPayloadAsStr := "2006002b000002001500080002f82900007a8000140017000000630002f8290007ab50102002f829000001000133"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsConverters.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusResponseConverterPduOfFailure(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsConverters := NewResourceStatusResponseConverter(unpacker)
+
+       wantError := "unexpected PDU, 3"
+       inputPayloadAsStr := "400900170000030027000300000000280003000049000540020a80"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsConverters.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusResponseConverterWrongPdu(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       rsConverters := NewResourceStatusResponseConverter(unpacker)
+
+       wantError := "unexpected PDU - not a resource status response"
+       inputPayloadAsStr := "2006002a000002001500080002f82900007a8000140017000000630002f8290007ab50102002f829000001000133"
+       var payload []byte
+       _, err := fmt.Sscanf(inputPayloadAsStr, "%x", &payload)
+       if err != nil {
+               t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
+       }
+
+       _, err = rsConverters.Convert(payload)
+       if err != nil {
+               if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
+                       t.Errorf("want failure: %s, got: %s", wantError, err)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
index 20e5de4..3952532 100644 (file)
@@ -31,43 +31,37 @@ import (
        "unsafe"
 )
 
-type Asn1PduUnpacker interface {
-       UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error)
-}
-
 type X2apPduUnpacker struct {
-       logger *logger.Logger
-
+       logger               *logger.Logger
+       maxMessageBufferSize int
 }
 
-func NewX2apPduUnpacker(logger *logger.Logger) Asn1PduUnpacker {
-       return &X2apPduUnpacker{logger :logger}
+func NewX2apPduUnpacker(logger *logger.Logger, maxMessageBufferSize int) X2apPduUnpacker {
+       return X2apPduUnpacker{logger: logger, maxMessageBufferSize: maxMessageBufferSize}
 }
 
-func (r X2apPduUnpacker) UnpackX2apPdu(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*C.E2AP_PDU_t, error) {
+func (r X2apPduUnpacker) UnpackX2apPdu(packedBuf []byte) (*C.E2AP_PDU_t, error) {
        pdu := C.new_pdu()
 
        if pdu == nil {
                return nil, errors.New("allocation failure (pdu)")
        }
 
-       r.logger.Infof("#x2apPdu_asn1_unpacker.UnpackX2apPdu - Packed pdu(%d):%x", packedBufferSize, packedBuf)
-
-       errBuf := make([]C.char, maxMessageBufferSize)
-       if !C.per_unpack_pdu(pdu, C.ulong(packedBufferSize), (*C.uchar)(unsafe.Pointer(&packedBuf[0])), C.ulong(len(errBuf)), &errBuf[0]) {
+       errBuf := make([]C.char, r.maxMessageBufferSize)
+       if !C.per_unpack_pdu(pdu, C.ulong(len(packedBuf)), (*C.uchar)(unsafe.Pointer(&packedBuf[0])), C.ulong(len(errBuf)), &errBuf[0]) {
                return nil, errors.New(fmt.Sprintf("unpacking error: %s", C.GoString(&errBuf[0])))
        }
 
        if r.logger.DebugEnabled() {
                C.asn1_pdu_printer(pdu, C.size_t(len(errBuf)), &errBuf[0])
-               r.logger.Debugf("#x2apPdu_asn1_unpacker.UnpackX2apPdu - PDU: %v  packed size:%d", C.GoString(&errBuf[0]), packedBufferSize)
+               r.logger.Debugf("#x2apPdu_asn1_unpacker.UnpackX2apPdu - PDU: %v  packed size:%d", C.GoString(&errBuf[0]), len(packedBuf))
        }
 
        return pdu, nil
 }
 
-func (r X2apPduUnpacker)UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error) {
-       pdu, err := r.UnpackX2apPdu(packedBufferSize, packedBuf, maxMessageBufferSize)
+func (r X2apPduUnpacker) UnpackX2apPduAsString(packedBuf []byte, maxMessageBufferSize int) (string, error) {
+       pdu, err := r.UnpackX2apPdu(packedBuf)
        if err != nil {
                return "", err
        }
@@ -78,6 +72,3 @@ func (r X2apPduUnpacker)UnpackX2apPduAsString(packedBufferSize int, packedBuf []
        C.asn1_pdu_printer(pdu, C.size_t(len(buf)), &buf[0])
        return C.GoString(&buf[0]), nil
 }
-
-
-
index 0792cf0..9c0dcdb 100644 (file)
@@ -36,7 +36,7 @@ import (
 
 func TestUnpackX2apPduResponse(t *testing.T) {
        logger, _ := logger.InitLogger(logger.DebugLevel)
-       unpacker := NewX2apPduUnpacker(logger)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
 
        wantPduAsStr := `UnsuccessfulOutcome ::= {
     procedureCode: 9
@@ -96,7 +96,7 @@ func TestUnpackX2apPduResponse(t *testing.T) {
                t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
        }
 
-       response, err := unpacker.UnpackX2apPduAsString(len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
+       response, err := unpacker.UnpackX2apPduAsString(payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
        if err != nil {
                t.Errorf("want: success, got: unpack failed. Error: %v\n", err)
        }
@@ -118,7 +118,7 @@ func TestUnpackX2apPduResponse(t *testing.T) {
 
 func TestUnpackX2apPduError(t *testing.T) {
        logger, _ := logger.InitLogger(logger.InfoLevel)
-       unpacker := NewX2apPduUnpacker(logger)
+       unpacker := NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
 
        wantError := "unpacking error: #src/asn1codec_utils.c.unpack_pdu_aux - Failed to decode E2AP-PDU (consumed 0), error = 0 Success"
        //--------------------2006002a
@@ -129,7 +129,7 @@ func TestUnpackX2apPduError(t *testing.T) {
                t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
        }
 
-       _, err = unpacker.UnpackX2apPduAsString(len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
+       _, err = unpacker.UnpackX2apPduAsString(payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
        if err != nil {
                if 0 != strings.Compare(fmt.Sprintf("%s", err), wantError) {
                        t.Errorf("want failure: %s, got: %s", wantError, err)
index 490e62e..d0da36c 100644 (file)
@@ -23,6 +23,7 @@ package e2pdus
 
 // #cgo CFLAGS: -I../3rdparty/asn1codec/inc/ -I../3rdparty/asn1codec/e2ap_engine/
 // #cgo LDFLAGS: -L ../3rdparty/asn1codec/lib/ -L../3rdparty/asn1codec/e2ap_engine/ -le2ap_codec -lasncodec
+// #include <stdlib.h>
 // #include <asn1codec_utils.h>
 // #include <resource_status_request_wrapper.h>
 import "C"
@@ -41,7 +42,7 @@ const (
 type Measurement_ID int64
 
 type ResourceStatusRequestData struct {
-       CellID                       string // PLMNIdentifier:eUTRANCellIdentifier
+       CellIdList                   []string // PLMNIdentifier:eUTRANCellIdentifier
        MeasurementID                Measurement_ID
        MeasurementID2               Measurement_ID
        PartialSuccessAllowed        bool
@@ -63,18 +64,34 @@ func BuildPackedResourceStatusRequest(registrationRequest enums.Registration_Req
        packedBufSize := C.ulong(len(packedBuf))
        pduAsString := ""
 
-       var pLMNIdentifier, eUTRANCellIdentifier string
+       pLMNIdentities := make([]*C.uchar, len(request.CellIdList))
+       eUTRANCellIdentifiers := make([]*C.uchar, len(request.CellIdList))
 
-       if _, err := fmt.Sscanf(request.CellID, "%x:%x", &pLMNIdentifier, &eUTRANCellIdentifier); err != nil {
-               return nil, "", fmt.Errorf("BuildPackedResourceStatusRequest() - unexpected CellID value [%s] (want: \"<PLMNIdentifier>:<eUTRANCellIdentifier>\"), err: %s", request.CellID, err)
+       for i, cellID := range request.CellIdList {
+               var pLMNIdentity, eUTRANCellIdentifier []byte
+               if _, err := fmt.Sscanf(cellID, "%x:%x", &pLMNIdentity, &eUTRANCellIdentifier); err != nil {
+                       return nil, "", fmt.Errorf("BuildPackedResourceStatusRequest() - unexpected CellID value [%s]@%d (want: \"<PLMNIdentifier>:<eUTRANCellIdentifier>\"), err: %s", cellID, i, err)
+               }
+               pLMNIdentities[i], eUTRANCellIdentifiers[i] = (*C.uchar)(C.CBytes(pLMNIdentity)), (*C.uchar)(C.CBytes(eUTRANCellIdentifier))
        }
 
+       defer func() {
+               for _, cPtr := range pLMNIdentities {
+                       C.free(unsafe.Pointer(cPtr))
+
+               }
+               for _, cPtr := range eUTRANCellIdentifiers {
+                       C.free(unsafe.Pointer(cPtr))
+               }
+
+       }()
+
        /*
-       9.2.0   General
-       When specifying information elements which are to be represented by bit strings, if not otherwise specifically stated in the semantics description of the concerned IE or elsewhere, the following principle applies with regards to the ordering of bits:
-       -       The first bit (leftmost bit) contains the most significant bit (MSB);
-       -       The last bit (rightmost bit) contains the least significant bit (LSB);
-       -       When importing bit strings from other specifications, the first bit of the bit string contains the first bit of the concerned information.
+               9.2.0   General
+               When specifying information elements which are to be represented by bit strings, if not otherwise specifically stated in the semantics description of the concerned IE or elsewhere, the following principle applies with regards to the ordering of bits:
+               -       The first bit (leftmost bit) contains the most significant bit (MSB);
+               -       The last bit (rightmost bit) contains the least significant bit (LSB);
+               -       When importing bit strings from other specifications, the first bit of the bit string contains the first bit of the concerned information.
 
        */
        /*reportCharacteristics:
@@ -118,8 +135,9 @@ func BuildPackedResourceStatusRequest(registrationRequest enums.Registration_Req
        reportCharacteristics := uint32(prbPeriodic<<7 | tnlLoadIndPeriodic<<6 | hwLoadIndPeriodic<<5 | compositeAvailablCapacityPeriodic<<4 | absStatusPeriodic<<3 | rsrpMeasurementPeriodic<<2 | csiPeriodic<<1)
 
        if !C.build_pack_resource_status_request(
-               (*C.uchar)(unsafe.Pointer(&[]byte(pLMNIdentifier)[0])),
-               (*C.uchar)(unsafe.Pointer(&[]byte(eUTRANCellIdentifier)[0])),
+               (**C.uchar)(unsafe.Pointer(&pLMNIdentities[0])),
+               (**C.uchar)(unsafe.Pointer(&eUTRANCellIdentifiers[0])),
+               C.ulong(len(request.CellIdList)),
                C.Measurement_ID_t(request.MeasurementID),
                C.Measurement_ID_t(request.MeasurementID2),
                C.Registration_Request_t(registrationRequest),
index 47e6f0b..3a878cc 100644 (file)
@@ -29,8 +29,8 @@ import (
 )
 
 /*
- * Create and pack an x2ap setup request.
- * Verify the packed representation matches the want value.
+* Create and pack an x2ap setup request.
+* Verify the packed representation matches the want value.
  */
 func TestBuildPackedResourceStatusRequest(t *testing.T) {
        var testCases = []struct {
@@ -39,7 +39,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
        }{
                {
                        request: ResourceStatusRequestData{
-                               CellID:                                           "0a0b0c:abcd8000",
+                               CellIdList:                   []string{"0a0b0c:abcd8000"},
                                MeasurementID:                15,
                                MeasurementID2:               0,
                                PartialSuccessAllowed:        true,
@@ -57,7 +57,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
                },
                {
                        request: ResourceStatusRequestData{
-                               CellID:                                           "0a0b0c:abcd8000",
+                               CellIdList:                   []string{"0a0b0c:abcd8000"},
                                MeasurementID:                15,
                                MeasurementID2:               0,
                                PartialSuccessAllowed:        true,
@@ -75,7 +75,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
                },
                {
                        request: ResourceStatusRequestData{
-                               CellID:                                           "0a0b0c:abcd8000",
+                               CellIdList:                   []string{"0a0b0c:abcd8000"},
                                MeasurementID:                15,
                                MeasurementID2:               0,
                                PartialSuccessAllowed:        true,
@@ -93,7 +93,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
                },
                {
                        request: ResourceStatusRequestData{
-                               CellID:                                           "0a0b0c:abcd8000",
+                               CellIdList:                   []string{"0a0b0c:abcd8000"},
                                MeasurementID:                15,
                                MeasurementID2:               0,
                                PartialSuccessAllowed:        false,
@@ -109,6 +109,24 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
                        },
                        packedPdu: "000900370000070027000300000e001c000100002600040e000000001d400d00001f4008000a0b0cabcd8000001e400160006d4001600091400140",
                },
+               {
+                       request: ResourceStatusRequestData{
+                               CellIdList:                   []string{"0a0b0c:abcd8000", "0b0c0d:acde8000"},
+                               MeasurementID:                15,
+                               MeasurementID2:               0,
+                               PartialSuccessAllowed:        true,
+                               PrbPeriodic:                  true,
+                               TnlLoadIndPeriodic:           true,
+                               HwLoadIndPeriodic:            true,
+                               AbsStatusPeriodic:            true,
+                               RsrpMeasurementPeriodic:      true,
+                               CsiPeriodic:                  true,
+                               PeriodicityMS:                enums.ReportingPeriodicity_one_thousand_ms,
+                               PeriodicityRsrpMeasurementMS: enums.ReportingPeriodicityRSRPMR_one_hundred_20_ms,
+                               PeriodicityCsiMS:             enums.ReportingPeriodicityCSIR_ms5,
+                       },
+                       packedPdu: "000900480000080027000300000e001c00010000260004fe000000001d401901001f4008000a0b0cabcd8000001f4008000b0c0dacde8000001e4001000040400100006d4001000091400100",
+               },
        }
 
        for _, tc := range testCases {
@@ -118,7 +136,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
                        if err != nil {
                                t.Errorf("want: success, got: pack failed. Error: %v\n", err)
                        } else {
-                               t.Logf("packed resource status request (size=%d): %x\n\n%s", len(payload), payload,asString)
+                               t.Logf("packed resource status request (size=%d): %x\n\n%s", len(payload), payload, asString)
                                tmp := fmt.Sprintf("%x", payload)
                                if len(tmp) != len(tc.packedPdu) {
                                        t.Errorf("want packed len:%d, got: %d\n", len(tc.packedPdu)/2, len(payload)/2)
@@ -136,7 +154,7 @@ func TestBuildPackedResourceStatusRequest(t *testing.T) {
 
 func TestBuildPackedResourceStatusRequestError(t *testing.T) {
        request := ResourceStatusRequestData{
-               CellID:                                           "0a0b0c:abcd8000",
+               CellIdList:                   []string{"0a0b0c:abcd8000"},
                MeasurementID:                15,
                MeasurementID2:               0,
                PrbPeriodic:                  true,
@@ -149,7 +167,7 @@ func TestBuildPackedResourceStatusRequestError(t *testing.T) {
                PeriodicityRsrpMeasurementMS: enums.ReportingPeriodicityRSRPMR_one_hundred_20_ms,
                PeriodicityCsiMS:             enums.ReportingPeriodicityCSIR_ms5,
        }
-       expected:= "packing error: #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big"
+       expected := "packing error: #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big"
        _, _, err := BuildPackedResourceStatusRequest(enums.Registration_Request_start, &request, 40 /*max packed buffer*/, MaxAsn1CodecMessageBufferSize /*max message buffer*/, true /*withDebug*/)
        if err != nil {
                if !strings.Contains(err.Error(), expected) {
@@ -163,7 +181,7 @@ func TestBuildPackedResourceStatusRequestError(t *testing.T) {
 
 func TestBuildPackedResourceStatusInvalidCellID(t *testing.T) {
        request := ResourceStatusRequestData{
-               CellID:                                           "0a0b0cabcd8000",
+               CellIdList:                   []string{"0a0b0cabcd8000"},
                MeasurementID:                15,
                MeasurementID2:               0,
                PrbPeriodic:                  true,
@@ -176,7 +194,7 @@ func TestBuildPackedResourceStatusInvalidCellID(t *testing.T) {
                PeriodicityRsrpMeasurementMS: enums.ReportingPeriodicityRSRPMR_one_hundred_20_ms,
                PeriodicityCsiMS:             enums.ReportingPeriodicityCSIR_ms5,
        }
-       expected:= "BuildPackedResourceStatusRequest() - unexpected CellID value [0a0b0cabcd8000] (want: \"<PLMNIdentifier>:<eUTRANCellIdentifier>\"), err: unexpected EOF"
+       expected := "BuildPackedResourceStatusRequest() - unexpected CellID value [0a0b0cabcd8000]@0 (want: \"<PLMNIdentifier>:<eUTRANCellIdentifier>\"), err: unexpected EOF"
        _, _, err := BuildPackedResourceStatusRequest(enums.Registration_Request_start, &request, MaxAsn1PackedBufferSize /*max packed buffer*/, MaxAsn1CodecMessageBufferSize /*max message buffer*/, true /*withDebug*/)
        if err != nil {
                if !strings.Contains(err.Error(), expected) {
@@ -190,7 +208,7 @@ func TestBuildPackedResourceStatusInvalidCellID(t *testing.T) {
 
 func TestBuildPackedResourceStatusInvalidPeriodicity(t *testing.T) {
        request := ResourceStatusRequestData{
-               CellID:                                           "0a0b0c:abcd8000",
+               CellIdList:                   []string{"0a0b0c:abcd8000"},
                MeasurementID:                15,
                MeasurementID2:               0,
                PrbPeriodic:                  true,
@@ -203,7 +221,54 @@ func TestBuildPackedResourceStatusInvalidPeriodicity(t *testing.T) {
                PeriodicityRsrpMeasurementMS: enums.ReportingPeriodicityRSRPMR_one_hundred_20_ms,
                PeriodicityCsiMS:             enums.ReportingPeriodicityCSIR_ms5,
        }
-       expected:= "BuildPackedResourceStatusRequest - packing error: #src/asn1codec_utils.c.pack_pdu_aux - Failed to encode E2AP-PDU, error = 9 Bad file descriptor"
+       expected := "BuildPackedResourceStatusRequest - packing error: #src/asn1codec_utils.c.pack_pdu_aux - Failed to encode E2AP-PDU, error = 9 Bad file descriptor"
+       _, _, err := BuildPackedResourceStatusRequest(enums.Registration_Request_start, &request, MaxAsn1PackedBufferSize /*max packed buffer*/, MaxAsn1CodecMessageBufferSize /*max message buffer*/, true /*withDebug*/)
+       if err != nil {
+               if !strings.Contains(err.Error(), expected) {
+                       t.Errorf("want failure:[%s], got: [%s]\n", expected, err)
+               }
+       } else {
+               t.Errorf("want failure: ...%s..., got: success", expected)
+
+       }
+}
+
+func TestBuildPackedResourceStatusTooManyCells(t *testing.T) {
+       request := ResourceStatusRequestData{
+               CellIdList: []string{
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000", "0a0b0c:abcd8000", "0b0c0d:acde8000",
+                       "0a0b0c:abcd8000",
+               },
+               MeasurementID:                15,
+               MeasurementID2:               0,
+               PartialSuccessAllowed:        true,
+               PrbPeriodic:                  true,
+               TnlLoadIndPeriodic:           true,
+               HwLoadIndPeriodic:            true,
+               AbsStatusPeriodic:            true,
+               RsrpMeasurementPeriodic:      true,
+               CsiPeriodic:                  true,
+               PeriodicityMS:                enums.ReportingPeriodicity_one_thousand_ms,
+               PeriodicityRsrpMeasurementMS: enums.ReportingPeriodicityRSRPMR_one_hundred_20_ms,
+               PeriodicityCsiMS:             enums.ReportingPeriodicityCSIR_ms5,
+       }
+
+       expected := "BuildPackedResourceStatusRequest - packing error: #src/asn1codec_utils.c.pack_pdu_aux - Failed to encode E2AP-PDU, error = 9 Bad file descriptor"
        _, _, err := BuildPackedResourceStatusRequest(enums.Registration_Request_start, &request, MaxAsn1PackedBufferSize /*max packed buffer*/, MaxAsn1CodecMessageBufferSize /*max message buffer*/, true /*withDebug*/)
        if err != nil {
                if !strings.Contains(err.Error(), expected) {
diff --git a/RSM/enums/constants.go b/RSM/enums/constants.go
new file mode 100644 (file)
index 0000000..4e5d618
--- /dev/null
@@ -0,0 +1,21 @@
+//
+// 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 enums
+
+const Enb1MeasurementId int64 = 1
index 509292a..50c0d4f 100644 (file)
@@ -33,12 +33,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 {
@@ -51,9 +45,9 @@ func (md MessageDirection) MarshalJSON() ([]byte, error) {
        _, ok := messageDirectionEnumName[int32(md)]
 
        if !ok {
-               return nil,&json.UnsupportedValueError{}
+               return nil, &json.UnsupportedValueError{}
        }
 
-       v:= int32(md)
+       v := int32(md)
        return json.Marshal(v)
 }
index 5fcc9cd..4460363 100644 (file)
@@ -25,6 +25,8 @@ type Registration_Request int
 const (
        Registration_Request_start Registration_Request = iota
        Registration_Request_stop
-       Registration_Request_partial_stop
-       Registration_Request_add
 )
+
+func (rs Registration_Request) String() string {
+       return [...]string{"start", "stop"}[rs]
+}
\ No newline at end of file
index 9715469..adeab1f 100644 (file)
@@ -68,4 +68,3 @@ func GetReportingPeriodicityValuesAsKeys() []int {
 
        return keys
 }
-
diff --git a/RSM/enums/rsm_action.go b/RSM/enums/rsm_action.go
new file mode 100644 (file)
index 0000000..ab0e1f1
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// 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 enums
+
+type RsmAction string
+
+const (
+       Start RsmAction = "start"
+       Stop  RsmAction = "stop"
+)
index 4815afb..5b5d9c6 100644 (file)
@@ -2,19 +2,18 @@ module rsm
 
 require (
        cloud.google.com/go v0.46.3 // indirect
-       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23
-       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23
-       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23
-       gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.3.1
+       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.26
+       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.26
+       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.26
+       gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.5.0
        github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
        github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
        github.com/coreos/bbolt v1.3.3 // indirect
        github.com/coreos/etcd v3.3.15+incompatible // indirect
        github.com/coreos/go-semver v0.3.0 // indirect
        github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
-       github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
+       github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect
        github.com/gogo/protobuf v1.3.0 // indirect
-       github.com/golang/protobuf v1.3.2
        github.com/google/go-cmp v0.3.1 // indirect
        github.com/google/pprof v0.0.0-20190908185732-236ed259b199 // indirect
        github.com/google/uuid v1.1.1 // indirect
@@ -59,4 +58,4 @@ require (
        gopkg.in/yaml.v2 v2.2.2
 )
 
-replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1
+replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0
index bc4bc33..0d3dd6b 100644 (file)
@@ -12,12 +12,27 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23 h1:JbSOhvj9fVEUF2XZg8cw5QAyeKUi5xXgpwXrrxfDgLM=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.24 h1:tW817tat6fSSK7NuFKEDHSoSsO3z8kr7QORfbn1Hpuc=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.24/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.25/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.26 h1:OQs1i2pNH85IxGiEsN/0yNUzTfiTgGVZwgvmfrkAhds=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.26/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23 h1:akVZc8NWJ9oPujd7cQY3Ti3se4PF1/NoC+Dwt+YzINc=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23/go.mod h1:GXiXLz4ORBeIr0FLIbzENRykgh3Po5uPkX2jICxnRF0=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.24 h1:5ZnhEUygvN5PuTXS2bNt6KavT+Wtuh9Vra+EqZIvw+Q=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.24/go.mod h1:GXiXLz4ORBeIr0FLIbzENRykgh3Po5uPkX2jICxnRF0=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.26 h1:8buj1aJBkoHPFQPfcCJ2MiL9VjdA5iR1kcc1CzNFB00=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.26/go.mod h1:Fh23KkroYw5CRBh39WzZzxpKSkpQWL3scdzGnMngLo8=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23 h1:TYV3HE2UNwGOWiA4C226/WhB94crwjuHKIFTgDDvo8I=
 gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23/go.mod h1:uZVjwZjfWV4JJzyQVO/O48Ykph57zfpfMB7nK+WGKX8=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.24 h1:Wwp36IoHwp091lXVCYLtFK6AMhoGAR4NYEgW1C42h6k=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.24/go.mod h1:Qi0e0BsGtsMdyJQS0PBtvHBDKEimjtDjQtVUxGZqTtM=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.26 h1:zGKpxfqz7Ql4rpD53JcWmDTwILrZfe0GIdi/QMslUew=
+gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.26/go.mod h1:DCf5H9yy6kNTXsnUgXAPSuJt22ca4pYm0mo2ovJhLrA=
 gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1 h1:ZIhABs0WLMn8lp1Y3719315/3jbV+yLcovOGScL03eM=
 gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1/go.mod h1:y2WhrCvdLkAKdH+ySdHSOSehACJkTMyZghCGVcqoZzc=
+gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0 h1:+P3XuWKSaMbzh5PNtrW9gkZlCN0hKrZq+Cn8JetwBys=
+gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0/go.mod h1:y2WhrCvdLkAKdH+ySdHSOSehACJkTMyZghCGVcqoZzc=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
index 6802c23..2fd683d 100644 (file)
@@ -25,5 +25,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..4d0575f
--- /dev/null
@@ -0,0 +1,159 @@
+//
+// 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 {
+
+               ranName := (*nbIdentity).GetInventoryName()
+
+               nodeb, err := h.rNibDataService.GetNodeb(ranName)
+               if err != nil {
+                       h.logger.Errorf("#ResourceStatusRequestHandler.Handle - Couldn't find RAN %s in RSM DB", ranName)
+                       numberOfFails++
+                       continue
+               }
+
+               h.logger.Infof("#ResourceStatusRequestHandler.Handle - handle RAN: %s started", nodeb.RanName)
+
+               if nodeb.ConnectionStatus != entities.ConnectionStatus_CONNECTED {
+                       h.logger.Infof("#ResourceStatusRequestHandler.Handle - RAN name: %s - connection status not CONNECTED, ignore", nodeb.RanName)
+                       h.logger.Infof("#ResourceStatusRequestHandler.Handle - handle RAN: %s completed", nodeb.RanName)
+                       continue
+               }
+
+               err = h.saveAndSendRsmRanInfo(nodeb, config)
+               if err != nil {
+                       numberOfFails++
+               }
+               h.logger.Infof("#ResourceStatusRequestHandler.Handle - handle RAN: %s completed", nodeb.RanName)
+       }
+
+       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 {
+               return h.handleNotStartedRsmRanInfo(nodebInfo, rsmRanInfo, config)
+       }
+
+       return h.handleNotStoppedRsmRanInfo(nodebInfo, rsmRanInfo, config)
+}
+
+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.Enb2MeasurementId == 0 {
+               h.logger.Errorf("#ResourceStatusRequestHandler.handleNotStoppedRsmRanInfo - RAN: %s Enb2MeasurementId is zero", nodebInfo.RanName)
+               return rsmerrors.NewInternalError()
+       }
+
+       if rsmRanInfo.Action != enums.Stop {
+
+               err := h.saveRsmRanInfoStopFalse(rsmRanInfo)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return h.resourceStatusService.BuildAndSendStopRequest(nodebInfo, config, rsmRanInfo.Enb1MeasurementId, rsmRanInfo.Enb2MeasurementId)
+}
+
+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
+               }
+       }
+
+       return h.resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, config, rsmRanInfo.Enb1MeasurementId)
+}
+
+func (h ResourceStatusRequestHandler) saveRsmRanInfoStopFalse(rsmRanInfo *models.RsmRanInfo) error {
+       rsmRanInfo.Action = enums.Stop
+       rsmRanInfo.ActionStatus = false
+
+       return h.rNibDataService.SaveRsmRanInfo(rsmRanInfo)
+}
+
+func (h ResourceStatusRequestHandler) saveRsmRanInfoStartFalse(rsmRanInfo *models.RsmRanInfo) error {
+       rsmRanInfo.Action = enums.Start
+       rsmRanInfo.ActionStatus = false
+       rsmRanInfo.Enb2MeasurementId = 0
+       rsmRanInfo.Enb1MeasurementId = enums.Enb1MeasurementId
+
+       return h.rNibDataService.SaveRsmRanInfo(rsmRanInfo)
+}
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..0dbc012
--- /dev/null
@@ -0,0 +1,406 @@
+//
+// 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 TestResourceStatusRequestHandlerTrueNumberOfFails1(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(1)
+       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(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:2, Action:enums.Stop, ActionStatus:false}
+       rrInfo2 := &models.RsmRanInfo{RanName:"RanName_2", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:2, Action:enums.Stop, ActionStatus:true}
+       rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:2, Action:enums.Start, 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, rrInfo1.Enb1MeasurementId, rrInfo1.Enb2MeasurementId).Return(nil)
+       resourceStatusServiceMock.On("BuildAndSendStopRequest", nb3, config, rrInfo3.Enb1MeasurementId, rrInfo3.Enb2MeasurementId).Return(nil)
+
+
+       resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:false}
+       actualErr := handler.Handle(resourceStatusRequest)
+
+       readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendStopRequest", 2)
+
+       assert.Equal(t, actualErr, nil)
+}
+
+func TestResourceStatusRequestHandlerFalseNumberOfFails1(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:2, Action:enums.Stop, ActionStatus:false}
+       rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:2, Action:enums.Start, 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("BuildAndSendStopRequest", nb3, config, rrInfo3.Enb1MeasurementId, rrInfo3.Enb2MeasurementId).Return(nil)
+
+
+       resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:false}
+       actualErr := handler.Handle(resourceStatusRequest)
+
+       readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendStopRequest", 1)
+
+       rsmError := rsmerrors.NewRsmError(1)
+       assert.Equal(t, actualErr, rsmError)
+       assert.Equal(t, actualErr.Error(), rsmError.Error())
+}
+
+func TestResourceStatusRequestHandlerFalseNumberOfFails3(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:2, Action:enums.Stop, ActionStatus:false}
+       rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:2, Action:enums.Start, 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("BuildAndSendStopRequest", nb1, config, rrInfo1.Enb1MeasurementId, rrInfo1.Enb2MeasurementId).Return(errors.New("Error"))
+
+       resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:false}
+       actualErr := handler.Handle(resourceStatusRequest)
+
+       readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendStopRequest", 1)
+
+       rsmError := rsmerrors.NewRsmError(3)
+       assert.Equal(t, actualErr, rsmError)
+       assert.Equal(t, actualErr.Error(), rsmError.Error())
+}
+
+func TestResourceStatusRequestHandlerFalseNoEnb2MeasurementId(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:2, Action:enums.Stop, ActionStatus:false}
+       rrInfo2 := &models.RsmRanInfo{RanName:"RanName_2", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:2, Action:enums.Stop, ActionStatus:true}
+       rrInfo3 := &models.RsmRanInfo{RanName:"RanName_3", Enb1MeasurementId:enums.Enb1MeasurementId, Enb2MeasurementId:0, Action:enums.Start, 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)
+
+       resourceStatusServiceMock.On("BuildAndSendStopRequest", nb1, config, rrInfo1.Enb1MeasurementId, rrInfo1.Enb2MeasurementId).Return(nil)
+
+       resourceStatusRequest := models.ResourceStatusRequest{EnableResourceStatus:false}
+       actualErr := handler.Handle(resourceStatusRequest)
+
+       readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 0)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendStopRequest", 1)
+
+       rsmError := rsmerrors.NewRsmError(1)
+       assert.Equal(t, actualErr, rsmError)
+       assert.Equal(t, actualErr.Error(), rsmError.Error())
+}
+
+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 5f31c6d..1a035a3 100644 (file)
@@ -28,25 +28,46 @@ import (
 )
 
 type ResourceStatusFailureHandler struct {
-       logger *logger.Logger
-       unpacker converters.Asn1PduUnpacker
+       logger    *logger.Logger
+       converter converters.IResourceStatusResponseConverter
 }
 
-func NewResourceStatusFailureHandler(logger *logger.Logger, unpacker converters.Asn1PduUnpacker) ResourceStatusFailureHandler {
+func NewResourceStatusFailureHandler(logger *logger.Logger, converter converters.IResourceStatusResponseConverter) ResourceStatusFailureHandler {
        return ResourceStatusFailureHandler{
-               logger:logger,
-               unpacker: unpacker,
+               logger:    logger,
+               converter: converter,
        }
 }
 
 func (h ResourceStatusFailureHandler) Handle(request *models.RmrRequest) {
        h.logger.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - Received resource status failure notification", request.RanName)
-       pduAsString, err := h.unpacker.UnpackX2apPduAsString(request.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
-       if err != nil {
-               h.logger.Errorf("#ResourceStatusFailureHandler.Handle - unpack failed. Error: %v", err)
-       } else {
-               h.logger.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - message: %s", request.RanName, pduAsString)
+       if h.logger.DebugEnabled() {
+               pduAsString, err := h.converter.UnpackX2apPduAsString(request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
+               if err != nil {
+                       h.logger.Errorf("#ResourceStatusFailureHandler.Handle - RAN name: %s - unpack failed. Error: %v", request.RanName, err)
+                       return
+               }
+               h.logger.Debugf("#ResourceStatusFailureHandler.Handle - RAN name: %s - message: %s", request.RanName, pduAsString)
        }
+       //response, err := h.converter.Convert(request.Payload)
+       //if err != nil {
+       //      h.logger.Errorf("#ResourceStatusFailureHandler.Handle - RAN name: %s - unpack failed. Error: %v", request.RanName, err)
+       //      return
+       //}
+       //
+       ///*The RSM creates one measurement per cell*/
+       //
+       //if response.MeasurementInitiationResults == nil {
+       //      h.logger.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - ENB1_Measurement_ID: %d, ENB2_Measurement_ID: %d",
+       //              request.RanName,
+       //              response.ENB1_Measurement_ID,
+       //              response.ENB2_Measurement_ID)
+       //} else {
+       //      h.logger.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - ENB1_Measurement_ID: %d, ENB2_Measurement_ID: %d, CellId: %s, FailedReportCharacteristics: %x",
+       //              request.RanName,
+       //              response.ENB1_Measurement_ID,
+       //              response.ENB2_Measurement_ID,
+       //              response.MeasurementInitiationResults[0].CellId,
+       //              response.MeasurementInitiationResults[0].MeasurementFailureCauses[0].MeasurementFailedReportCharacteristics)
+       //}
 }
-
-
index b4db47f..1a79fab 100644 (file)
 
 package rmrmsghandlers
 
-import (
-       "fmt"
-       "rsm/e2pdus"
-       "rsm/logger"
-       "rsm/mocks"
-       "rsm/models"
-       "testing"
-       "time"
-)
-
-// Verify UnpackX2apPduAsString is called
-func TestFailureHandler(t *testing.T) {
-       logger, err := logger.InitLogger(logger.DebugLevel)
+// Verify UnpackX2apPduAsString() and Convert() are called
+/*
+func TestResourceStatusFailureHandlerConvertFailure(t *testing.T) {
+       logger, err := logger.InitLogger(logger.InfoLevel)
        if err != nil {
                t.Errorf("#... - failed to initialize logger, error: %s", err)
        }
-       payload:= []byte("aaa")
-       req:= models.RmrRequest{RanName: "test", StartTime:time.Now(), Payload:payload,Len:len(payload)}
-       unpackerMock:=mocks.Asn1PduUnpackerMock{}
-       unpackerMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
-       h:= NewResourceStatusFailureHandler(logger, &unpackerMock)
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       converterMock := mocks.ResourceStatusFailureConverterMock{}
+       //converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+       h := NewResourceStatusFailureHandler(logger, &converterMock)
 
        h.Handle(&req)
 
-       unpackerMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       //converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
 }
 
 
-func TestFailureHandlerError(t *testing.T) {
+func TestResourceStatusFailureHandlerUnpackFailure(t *testing.T) {
        logger, err := logger.InitLogger(logger.DebugLevel)
        if err != nil {
                t.Errorf("#... - failed to initialize logger, error: %s", err)
        }
-       payload:= []byte("aaa")
-       req:= models.RmrRequest{RanName: "test", StartTime:time.Now(), Payload:payload,Len:len(payload)}
-       unpackerMock:=mocks.Asn1PduUnpackerMock{}
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       converterMock := mocks.ResourceStatusFailureConverterMock{}
 
        err = fmt.Errorf("error")
        var payloadAsString string
-       unpackerMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(payloadAsString, err)
-       h:= NewResourceStatusFailureHandler(logger, &unpackerMock)
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(payloadAsString, err)
+       converterMock.On("Convert", req.Payload).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+       h := NewResourceStatusFailureHandler(logger, &converterMock)
+
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 0)
+}
+*/
+
+/*
+func TestResourceStatusFailureHandler(t *testing.T) {
+       logger, err := logger.InitLogger(logger.InfoLevel)
+       if err != nil {
+               t.Errorf("#... - failed to initialize logger, error: %s", err)
+       }
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       converter := converters.NewResourceStatusFailureConverter(unpacker)
+       var payload []byte
+       fmt.Sscanf("400900320000040027000300000e0028000300000c00054001620044401800004540130002f8290007ab500000434006000000000740", "%x", &payload)
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       h := NewResourceStatusFailureHandler(logger, converter)
 
        h.Handle(&req)
+}
+
+func TestResourceStatusFailureHandlerMinimalPdu(t *testing.T) {
+       logger, err := logger.InitLogger(logger.InfoLevel)
+       if err != nil {
+               t.Errorf("#... - failed to initialize logger, error: %s", err)
+       }
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       converter := converters.NewResourceStatusFailureConverter(unpacker)
+       var payload []byte
+       fmt.Sscanf("400900170000030027000300000000280003000049000540020a80", "%x", &payload)
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       h := NewResourceStatusFailureHandler(logger, converter)
 
-       unpackerMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       h.Handle(&req)
 }
+*/
\ No newline at end of file
index 1d9cac7..8afd23e 100644 (file)
@@ -21,73 +21,107 @@ package rmrmsghandlers
 
 import (
        "encoding/json"
+       "fmt"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
-       "rsm/configuration"
-       "rsm/e2pdus"
+       "rsm/enums"
        "rsm/logger"
-       "rsm/managers"
        "rsm/models"
+       "rsm/services"
 )
 
 type ResourceStatusInitiateNotificationHandler struct {
-       logger                        *logger.Logger
-       config                        *configuration.Configuration
-       resourceStatusInitiateManager managers.IResourceStatusInitiateManager
-       requestName                   string
+       logger                *logger.Logger
+       rnibDataService       services.RNibDataService
+       resourceStatusService services.IResourceStatusService
+       requestName           string
 }
 
-func NewResourceStatusInitiateNotificationHandler(logger *logger.Logger, config *configuration.Configuration, resourceStatusInitiateManager managers.IResourceStatusInitiateManager, requestName string) ResourceStatusInitiateNotificationHandler {
+func NewResourceStatusInitiateNotificationHandler(logger *logger.Logger, rnibDataService services.RNibDataService, resourceStatusService services.IResourceStatusService, requestName string) ResourceStatusInitiateNotificationHandler {
        return ResourceStatusInitiateNotificationHandler{
-               logger:                        logger,
-               config:                        config,
-               resourceStatusInitiateManager: resourceStatusInitiateManager,
-               requestName:                   requestName,
+               logger:                logger,
+               rnibDataService:       rnibDataService,
+               resourceStatusService: resourceStatusService,
+               requestName:           requestName,
        }
 }
 
+func (h ResourceStatusInitiateNotificationHandler) UnmarshalResourceStatusPayload(inventoryName string, payload []byte) (*models.ResourceStatusPayload, error) {
+       unmarshalledPayload := models.ResourceStatusPayload{}
+       err := json.Unmarshal(payload, &unmarshalledPayload)
+
+       if err != nil {
+               h.logger.Errorf("#ResourceStatusInitiateNotificationHandler.UnmarshalResourceStatusPayload - RAN name: %s - Error unmarshaling RMR request payload: %v", inventoryName, err)
+               return nil, err
+       }
+
+       if unmarshalledPayload.NodeType == entities.Node_UNKNOWN {
+               h.logger.Errorf("#ResourceStatusInitiateNotificationHandler.UnmarshalResourceStatusPayload - RAN name: %s - Unknown Node Type", inventoryName)
+               return nil, fmt.Errorf("unknown node type for RAN %s", inventoryName)
+       }
+
+       h.logger.Infof("#ResourceStatusInitiateNotificationHandler.UnmarshalResourceStatusPayload - Unmarshaled payload successfully: %+v", unmarshalledPayload)
+       return &unmarshalledPayload, nil
+
+}
+
+func (h ResourceStatusInitiateNotificationHandler) SaveRsmRanInfoStopTrue(inventoryName string) {
+       rsmRanInfo := models.NewRsmRanInfo(inventoryName, 0, 0, enums.Stop, true)
+       _ = h.rnibDataService.SaveRsmRanInfo(rsmRanInfo)
+}
+
 func (h ResourceStatusInitiateNotificationHandler) Handle(request *models.RmrRequest) {
        inventoryName := request.RanName
-       h.logger.Infof("#ResourceStatusInitiateNotificationHandler - RAN name: %s - Received %s notification", inventoryName, h.requestName)
+       h.logger.Infof("#ResourceStatusInitiateNotificationHandler.Handle - RAN name: %s - Received %s notification", inventoryName, h.requestName)
+
+       payload, err := h.UnmarshalResourceStatusPayload(inventoryName, request.Payload)
 
-       if !isResourceStatusEnabled(h.config) {
-               h.logger.Warnf("#ResourceStatusInitiateNotificationHandler - RAN name: %s - resource status is disabled", inventoryName)
+       if err != nil {
                return
        }
 
-       payload := models.ResourceStatusPayload{}
-       err := json.Unmarshal(request.Payload, &payload)
+       if payload.NodeType != entities.Node_ENB {
+               h.logger.Debugf("#ResourceStatusInitiateNotificationHandler.Handle - RAN name: %s, Node type isn't ENB", inventoryName)
+               return
+       }
+
+       config, err := h.rnibDataService.GetRsmGeneralConfiguration()
 
        if err != nil {
-               h.logger.Errorf("#ResourceStatusInitiateNotificationHandler - RAN name: %s - Error unmarshaling RMR request payload: %v", inventoryName, err)
                return
        }
 
-       h.logger.Infof("#ResourceStatusInitiateNotificationHandler - Unmarshaled payload successfully: %+v", payload)
+       if !config.EnableResourceStatus {
+               h.SaveRsmRanInfoStopTrue(inventoryName)
+               return
+       }
 
-       if payload.NodeType != entities.Node_ENB {
-               h.logger.Debugf("#ResourceStatusInitiateNotificationHandler - RAN name: %s, Node type isn't ENB", inventoryName)
+       nodeb, err := h.rnibDataService.GetNodeb(inventoryName)
+
+       if err != nil {
                return
        }
 
-       resourceStatusInitiateRequestParams := &e2pdus.ResourceStatusRequestData{}
-       populateResourceStatusInitiateRequestParams(resourceStatusInitiateRequestParams, h.config)
+       nodebConnectionStatus := nodeb.GetConnectionStatus()
 
-       _ = h.resourceStatusInitiateManager.Execute(inventoryName, resourceStatusInitiateRequestParams)
-}
+       h.logger.Infof("#ResourceStatusInitiateNotificationHandler.Handle - RAN name: %s - successfully fetched RAN from db. RAN's connection status: %s", inventoryName, nodebConnectionStatus)
 
-func isResourceStatusEnabled(configuration *configuration.Configuration) bool {
-       return configuration.ResourceStatusParams.EnableResourceStatus
-}
+       if nodebConnectionStatus != entities.ConnectionStatus_CONNECTED {
+               h.logger.Errorf("#ResourceStatusInitiateNotificationHandler.Handle - RAN name: %s - RAN's connection status isn't CONNECTED", inventoryName)
+               h.SaveRsmRanInfoStopTrue(inventoryName)
+               return
+       }
+
+       rsmRanInfo := models.NewRsmRanInfo(inventoryName, enums.Enb1MeasurementId, 0, enums.Start, false)
+       err = h.rnibDataService.SaveRsmRanInfo(rsmRanInfo)
 
-func populateResourceStatusInitiateRequestParams(params *e2pdus.ResourceStatusRequestData, config *configuration.Configuration) {
-       params.PartialSuccessAllowed = config.ResourceStatusParams.PartialSuccessAllowed
-       params.PrbPeriodic = config.ResourceStatusParams.PrbPeriodic
-       params.TnlLoadIndPeriodic = config.ResourceStatusParams.TnlLoadIndPeriodic
-       params.HwLoadIndPeriodic = config.ResourceStatusParams.HwLoadIndPeriodic
-       params.AbsStatusPeriodic = config.ResourceStatusParams.AbsStatusPeriodic
-       params.RsrpMeasurementPeriodic = config.ResourceStatusParams.RsrpMeasurementPeriodic
-       params.CsiPeriodic = config.ResourceStatusParams.CsiPeriodic
-       params.PeriodicityMS = config.ResourceStatusParams.PeriodicityMs
-       params.PeriodicityRsrpMeasurementMS = config.ResourceStatusParams.PeriodicityRsrpMeasurementMs
-       params.PeriodicityCsiMS = config.ResourceStatusParams.PeriodicityCsiMs
+       if err != nil {
+               return
+       }
+
+       err = h.resourceStatusService.BuildAndSendInitiateRequest(nodeb, config, rsmRanInfo.Enb1MeasurementId)
+
+       if err != nil {
+               h.SaveRsmRanInfoStopTrue(inventoryName)
+               return
+       }
 }
index f6a3900..7549915 100644 (file)
 package rmrmsghandlers
 
 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/e2pdus"
+       "rsm/enums"
        "rsm/logger"
        "rsm/mocks"
        "rsm/models"
+       "rsm/services"
+       "rsm/tests"
        "testing"
        "time"
 )
 
-func initRanConnectedNotificationHandlerTest(t *testing.T, requestName string) (ResourceStatusInitiateNotificationHandler, *mocks.ResourceStatusInitiateManagerMock, *configuration.Configuration) {
+const RanName = "test"
+
+
+func initRanConnectedNotificationHandlerTest(t *testing.T, requestName string) (ResourceStatusInitiateNotificationHandler, *mocks.RnibReaderMock, *mocks.ResourceStatusServiceMock, *mocks.RsmWriterMock, *mocks.RsmReaderMock) {
        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)
        }
-       managerMock := &mocks.ResourceStatusInitiateManagerMock{}
-       h := NewResourceStatusInitiateNotificationHandler(log, config, managerMock, requestName)
-       return h, managerMock, config
+
+       resourceStatusServiceMock := &mocks.ResourceStatusServiceMock{}
+       rnibReaderMock := &mocks.RnibReaderMock{}
+       rsmReaderMock := &mocks.RsmReaderMock{}
+       rsmWriterMock := &mocks.RsmWriterMock{}
+
+       rnibDataService := services.NewRnibDataService(log, config, rnibReaderMock, rsmReaderMock, rsmWriterMock)
+
+       h := NewResourceStatusInitiateNotificationHandler(log, rnibDataService, resourceStatusServiceMock, requestName)
+       return h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock
 }
 
 func TestHandlerInit(t *testing.T) {
-       h, _, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       h, _, _, _, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
        assert.NotNil(t, h)
 }
 
-func TestHandleSuccess(t *testing.T) {
-       h, managerMock, config := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+func TestJsonUnmarshalError(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, _, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+
+       payloadStr := "blabla"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+
+       rnibReaderMock.On("GetNodeb", RanName).Return(mock.AnythingOfType("*entities.NodebInfo"))
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rnibReaderMock.AssertNumberOfCalls(t, "GetNodeb", 0)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
+
+func TestUnknownJsonValue(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, _, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+
+       payloadStr := "{\"whatever\":3}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+
+       rnibReaderMock.On("GetNodeb", RanName).Return(mock.AnythingOfType("*entities.NodebInfo"))
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rnibReaderMock.AssertNumberOfCalls(t, "GetNodeb", 0)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
+
+func TestHandleGnbNode(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, _, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
 
+       payloadStr := "{\"nodeType\":2, \"messageDirection\":1}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: "RAN1", Payload: payload, Len: len(payload), StartTime: time.Now()}
+       rnibReaderMock.On("GetNodeb", RanName).Return(mock.AnythingOfType("*entities.NodebInfo"))
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rnibReaderMock.AssertNumberOfCalls(t, "GetNodeb", 0)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
+
+func TestGetRsmGeneralConfigurationFailure(t *testing.T) {
+       h, _, resourceStatusServiceMock, _, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       var rgc models.RsmGeneralConfiguration
+       rsmReaderMock.On("GetRsmGeneralConfiguration").Return(&rgc, common.NewInternalError(errors.New("Error")))
        payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
        payload := []byte(payloadStr)
-       rmrReq := &models.RmrRequest{RanName:"RAN1", Payload:payload, Len:len(payload), StartTime:time.Now()}
-       managerMock.On("Execute", rmrReq.RanName, mock.AnythingOfType("*e2pdus.ResourceStatusRequestData")).Return(nil)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
 
-       resourceStatusInitiateRequestParams := &e2pdus.ResourceStatusRequestData{}
-       populateResourceStatusInitiateRequestParams(resourceStatusInitiateRequestParams, config)
+func TestEnableResourceStatusFalse(t *testing.T) {
+       h, _, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       var err error
+       rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(false), err)
+       rsmRanInfo := models.RsmRanInfo{RanName, 0, 0, enums.Stop, true}
+       rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(err)
 
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
        h.Handle(rmrReq)
-       managerMock.AssertCalled(t, "Execute", rmrReq.RanName, resourceStatusInitiateRequestParams)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
 }
 
-func TestHandleResourceStatusNotEnabled(t *testing.T) {
-       h, managerMock, config := initRanConnectedNotificationHandlerTest(t, "RanConnected")
-       config.ResourceStatusParams.EnableResourceStatus = false
+func TestEnableResourceStatusFalseSaveRsmRanInfoFailure(t *testing.T) {
+       h, _, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       var err error
+       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")))
 
        payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
        payload := []byte(payloadStr)
-       rmrReq := &models.RmrRequest{RanName:"RAN1", Payload:payload, Len:len(payload), StartTime:time.Now()}
-       managerMock.On("Execute", rmrReq.RanName, mock.AnythingOfType("*e2pdus.ResourceStatusRequestData")).Return(nil)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
 
+func TestGetNodebFailure(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, _, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+
+       var err error
+       rsmReaderMock.On("GetRsmGeneralConfiguration").Return(tests.GetRsmGeneralConfiguration(true), err)
+
+       var nodebInfo *entities.NodebInfo
+       rnibReaderMock.On("GetNodeb", RanName).Return(nodebInfo, common.NewInternalError(errors.New("Error")))
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
        h.Handle(rmrReq)
-       managerMock.AssertNumberOfCalls(t, "Execute", 0)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rnibReaderMock.AssertCalled(t, "GetNodeb", RanName)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
 }
 
-func TestHandleUnknownJson(t *testing.T) {
-       h, managerMock, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+func TestInvalidConnectionStatus(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       var err error
+       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)
 
-       payloadStr := "blablabla"
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
        payload := []byte(payloadStr)
-       rmrReq := &models.RmrRequest{RanName:"RAN1", Payload:payload, Len:len(payload), StartTime:time.Now()}
-       managerMock.On("Execute", rmrReq.RanName, mock.AnythingOfType("*e2pdus.ResourceStatusRequestData")).Return(nil)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rnibReaderMock.AssertCalled(t, "GetNodeb", RanName)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
+}
+
+func TestEnableResourceStatusTrueSaveRsmRanInfoFailure(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
 
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+
+       var err error
+       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")))
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", mock.AnythingOfType("*entities.NodebInfo"), mock.AnythingOfType("*models.RsmGeneralConfiguration"), enums.Enb1MeasurementId).Return(nil)
        h.Handle(rmrReq)
-       managerMock.AssertNumberOfCalls(t, "Execute", 0)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rnibReaderMock.AssertCalled(t, "GetNodeb", RanName)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 0)
 }
 
-func TestHandleGnbNode(t *testing.T) {
-       h, managerMock, _ := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+func TestBuildAndSendSuccess(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
 
-       payloadStr := "{\"nodeType\":2, \"messageDirection\":1}"
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
        payload := []byte(payloadStr)
-       rmrReq := &models.RmrRequest{RanName:"RAN1", Payload:payload, Len:len(payload), StartTime:time.Now()}
-       managerMock.On("Execute", rmrReq.RanName, mock.AnythingOfType("*e2pdus.ResourceStatusRequestData")).Return(nil)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
 
+       var err error
+       rgc := tests.GetRsmGeneralConfiguration(true)
+       rsmReaderMock.On("GetRsmGeneralConfiguration").Return(rgc, err)
+       nodebInfo := &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
+       rnibReaderMock.On("GetNodeb", RanName).Return(nodebInfo, err)
+       rsmRanInfo := models.RsmRanInfo{RanName, enums.Enb1MeasurementId, 0, enums.Start, false}
+       rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfo).Return(err)
+
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nodebInfo, rgc, enums.Enb1MeasurementId).Return(nil)
+       h.Handle(rmrReq)
+       rnibReaderMock.AssertCalled(t, "GetNodeb", RanName)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 1)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 1)
+}
+
+func TestBuildAndSendError(t *testing.T) {
+       h, rnibReaderMock, resourceStatusServiceMock, rsmWriterMock, rsmReaderMock := initRanConnectedNotificationHandlerTest(t, "RanConnected")
+       var err error
+       nodebInfo := &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED}
+       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}
+       rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfoStart).Return(err)
+       rsmRanInfoStop := models.RsmRanInfo{RanName, 0, 0, enums.Stop, true}
+       rsmWriterMock.On("SaveRsmRanInfo", &rsmRanInfoStop).Return(err)
+       payloadStr := "{\"nodeType\":1, \"messageDirection\":1}"
+       payload := []byte(payloadStr)
+       rmrReq := &models.RmrRequest{RanName: RanName, Payload: payload, Len: len(payload), StartTime: time.Now()}
+       resourceStatusServiceMock.On("BuildAndSendInitiateRequest", nodebInfo, rgc, enums.Enb1MeasurementId).Return(common.NewInternalError(errors.New("Error")))
        h.Handle(rmrReq)
-       managerMock.AssertNumberOfCalls(t, "Execute", 0)
+       rsmReaderMock.AssertCalled(t, "GetRsmGeneralConfiguration")
+       rnibReaderMock.AssertCalled(t, "GetNodeb", RanName)
+       resourceStatusServiceMock.AssertNumberOfCalls(t, "BuildAndSendInitiateRequest", 1)
+       rsmWriterMock.AssertNumberOfCalls(t, "SaveRsmRanInfo", 2)
 }
index 04c4dc7..5f32d58 100644 (file)
 
 package rmrmsghandlers
 
-
 import (
-//     "rsm/converters"
-//     "rsm/e2pdus"
+       "rsm/converters"
+       "rsm/e2pdus"
        "rsm/logger"
        "rsm/models"
+       "rsm/services"
 )
 
 type ResourceStatusResponseHandler struct {
-       logger *logger.Logger
+       logger          *logger.Logger
+       rnibDataService services.RNibDataService
+       converter       converters.IResourceStatusResponseConverter
 }
 
-func NewResourceStatusResponseHandler(logger *logger.Logger) ResourceStatusResponseHandler {
+func NewResourceStatusResponseHandler(logger *logger.Logger, converter converters.IResourceStatusResponseConverter, rnibDataService services.RNibDataService) ResourceStatusResponseHandler {
        return ResourceStatusResponseHandler{
-               logger:logger,
+               logger:          logger,
+               converter:       converter,
+               rnibDataService: rnibDataService,
        }
 }
 
 func (h ResourceStatusResponseHandler) Handle(request *models.RmrRequest) {
        h.logger.Infof("#ResourceStatusResponseHandler.Handle - RAN name: %s - Received resource status response notification", request.RanName)
-       //_, err := converters.UnpackX2apPduAsString(h.logger, request.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
-       //if err != nil {
-       //      logger.Errorf("#ResourceStatusResponseHandler.Handle - unpack failed. Error: %v", err)
-       //}
+
+       if h.logger.DebugEnabled() {
+               pduAsString, err := h.converter.UnpackX2apPduAsString(request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
+               if err != nil {
+                       h.logger.Errorf("#ResourceStatusResponseHandler.Handle - RAN name: %s - unpack failed. Error: %v", request.RanName, err)
+                       return
+               }
+               h.logger.Debugf("#ResourceStatusResponseHandler.Handle - RAN name: %s - pdu: %s", request.RanName, pduAsString)
+       }
+
+       response, err := h.converter.Convert(request.Payload)
+
+       if err != nil {
+               h.logger.Errorf("#ResourceStatusResponseHandler.Handle - RAN name: %s - unpack failed. Error: %v", request.RanName, err)
+               return
+       }
+
+       if response.ENB2_Measurement_ID == 0 {
+               h.logger.Errorf("#ResourceStatusResponseHandler.Handle - RAN name: %s - ignoring response without ENB2_Measurement_ID", request.RanName)
+               return
+       }
+
+       h.logger.Infof("#ResourceStatusResponseHandler.Handle - RAN name: %s - (success) ENB1_Measurement_ID: %d, ENB2_Measurement_ID: %d",
+               request.RanName,
+               response.ENB1_Measurement_ID,
+               response.ENB2_Measurement_ID)
+
+       rsmRanInfo, err := h.rnibDataService.GetRsmRanInfo(request.RanName)
+
+       if err != nil {
+               return
+       }
+
+       rsmRanInfo.Enb2MeasurementId = response.ENB2_Measurement_ID
+       rsmRanInfo.ActionStatus = true
+
+       err = h.rnibDataService.SaveRsmRanInfo(rsmRanInfo)
+
+       if err != nil {
+               return
+       }
+
+       h.logger.Infof("#ResourceStatusResponseHandler.Handle - RAN name: %s - Successfully updated RsmRanInfo", request.RanName)
 }
diff --git a/RSM/handlers/rmrmsghandlers/resource_status_response_handler_test.go b/RSM/handlers/rmrmsghandlers/resource_status_response_handler_test.go
new file mode 100644 (file)
index 0000000..2739be6
--- /dev/null
@@ -0,0 +1,151 @@
+//
+// 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 rmrmsghandlers
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
+       "github.com/pkg/errors"
+       "rsm/configuration"
+       "rsm/e2pdus"
+       "rsm/enums"
+       "rsm/logger"
+       "rsm/mocks"
+       "rsm/models"
+       "rsm/services"
+       "testing"
+       "time"
+)
+
+func initResourceStatusResponseHandlerTest(t *testing.T) (*mocks.ResourceStatusResponseConverterMock, ResourceStatusResponseHandler, *mocks.RsmReaderMock, *mocks.RsmWriterMock) {
+       logger, 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)
+       }
+
+       converterMock := &mocks.ResourceStatusResponseConverterMock{}
+
+       rnibReaderMock := &mocks.RnibReaderMock{}
+       rsmReaderMock := &mocks.RsmReaderMock{}
+       rsmWriterMock := &mocks.RsmWriterMock{}
+
+       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderMock, rsmReaderMock, rsmWriterMock)
+       h := NewResourceStatusResponseHandler(logger, converterMock, rnibDataService)
+
+       return converterMock, h, rsmReaderMock, rsmWriterMock
+
+}
+
+// Verify UnpackX2apPduAsString() and Convert() are called
+func TestResourceStatusResponseHandler(t *testing.T) {
+       converterMock, h, _, _ := initResourceStatusResponseHandlerTest(t)
+
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+
+       h.Handle(&req)
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+}
+
+func TestResourceStatusResponseHandlerConvertError(t *testing.T) {
+       converterMock, h, _, _ := initResourceStatusResponseHandlerTest(t)
+
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       err := fmt.Errorf("error")
+       var payloadAsString string
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(payloadAsString, err)
+       converterMock.On("Convert", req.Payload).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 0)
+}
+
+func TestResourceStatusResponseHandlerEnb2Mid0(t *testing.T) {
+       converterMock, h, _, _ := initResourceStatusResponseHandlerTest(t)
+
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: "test", StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       response := &models.ResourceStatusResponse{}
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return(response, nil)
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+}
+
+func TestResourceStatusResponseHandlerWithMidGetRsmRanInfoFailure(t *testing.T) {
+       converterMock, h, rsmReaderMock, rsmWriterMock := initResourceStatusResponseHandlerTest(t)
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: RanName, StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       response := &models.ResourceStatusResponse{ENB1_Measurement_ID: 1, ENB2_Measurement_ID: 2}
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return(response, nil)
+       rsmReaderMock.On("GetRsmRanInfo", RanName).Return(&models.RsmRanInfo{}, common.NewInternalError(errors.New("Error")))
+       h.Handle(&req)
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+       rsmReaderMock.AssertCalled(t, "GetRsmRanInfo", RanName)
+       rsmWriterMock.AssertNotCalled(t, "SaveRsmRanInfo")
+}
+
+func TestResourceStatusResponseHandlerWithMidUpdateFailure(t *testing.T) {
+       converterMock, h, rsmReaderMock, rsmWriterMock := initResourceStatusResponseHandlerTest(t)
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: RanName, StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       response := &models.ResourceStatusResponse{ENB1_Measurement_ID: 1, ENB2_Measurement_ID: 2}
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return(response, nil)
+       rsmRanInfoBefore := models.NewRsmRanInfo(RanName, enums.Enb1MeasurementId, 0, enums.Start, false)
+       rsmReaderMock.On("GetRsmRanInfo", RanName).Return(rsmRanInfoBefore, nil)
+       updatedRsmRanInfo := models.NewRsmRanInfo(RanName, enums.Enb1MeasurementId, response.ENB2_Measurement_ID, enums.Start, true)
+       rsmWriterMock.On("SaveRsmRanInfo", rsmRanInfoBefore).Return(common.NewInternalError(errors.New("Error")))
+       h.Handle(&req)
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+       rsmReaderMock.AssertCalled(t, "GetRsmRanInfo", RanName)
+       rsmWriterMock.AssertCalled(t, "SaveRsmRanInfo", updatedRsmRanInfo)
+}
+
+func TestResourceStatusResponseHandlerWithMidSuccessfulUpdate(t *testing.T) {
+       converterMock, h, rsmReaderMock, rsmWriterMock := initResourceStatusResponseHandlerTest(t)
+       payload := []byte("aaa")
+       req := models.RmrRequest{RanName: RanName, StartTime: time.Now(), Payload: payload, Len: len(payload)}
+       response := &models.ResourceStatusResponse{ENB1_Measurement_ID: 1, ENB2_Measurement_ID: 2}
+       converterMock.On("UnpackX2apPduAsString", req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Payload).Return(response, nil)
+       rsmRanInfoBefore := models.NewRsmRanInfo(RanName, enums.Enb1MeasurementId, 0, enums.Start, false)
+       rsmReaderMock.On("GetRsmRanInfo", RanName).Return(rsmRanInfoBefore, nil)
+       updatedRsmRanInfo := models.NewRsmRanInfo(RanName, enums.Enb1MeasurementId, response.ENB2_Measurement_ID, enums.Start, true)
+       rsmWriterMock.On("SaveRsmRanInfo", rsmRanInfoBefore).Return(nil)
+       h.Handle(&req)
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+       rsmReaderMock.AssertCalled(t, "GetRsmRanInfo", RanName)
+       rsmWriterMock.AssertCalled(t, "SaveRsmRanInfo", updatedRsmRanInfo /*&updatedRsmRanInfo*/)
+}
index 1b1275b..bb3155f 100644 (file)
@@ -26,4 +26,4 @@ import (
 
 type RmrMessageHandler interface {
        Handle(*models.RmrRequest)
-}
\ No newline at end of file
+}
index 5e2deea..95b47cb 100644 (file)
@@ -27,10 +27,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)
 
@@ -39,7 +39,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 1eb0c5a..813ac89 100644 (file)
@@ -30,17 +30,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 {
@@ -53,7 +68,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 {
@@ -66,18 +81,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")
index 1c1f933..610ee7f 100644 (file)
@@ -29,7 +29,7 @@ import (
 )
 
 type Logger struct {
-       Logger     *zap.Logger
+       Logger *zap.Logger
 }
 
 // Copied from zap logger
@@ -61,21 +61,21 @@ const (
        _maxLevel = FatalLevel
 )
 
-var logLevelTokenToLevel = map[string] LogLevel {
-       "debug" : DebugLevel,
-       "info": InfoLevel,
-       "warn": WarnLevel,
-       "error": ErrorLevel,
+var logLevelTokenToLevel = map[string]LogLevel{
+       "debug" DebugLevel,
+       "info":   InfoLevel,
+       "warn":   WarnLevel,
+       "error":  ErrorLevel,
        "dpanic": DPanicLevel,
-       "panic": PanicLevel,
-       "fatal": FatalLevel,
+       "panic":  PanicLevel,
+       "fatal":  FatalLevel,
 }
 
 func LogLevelTokenToLevel(level string) (LogLevel, bool) {
-       if level, ok := logLevelTokenToLevel[strings.TrimSpace(strings.ToLower(level))];ok {
+       if level, ok := logLevelTokenToLevel[strings.TrimSpace(strings.ToLower(level))]; ok {
                return level, true
        }
-       return _maxLevel+1, false
+       return _maxLevel + 1, false
 }
 
 func InitLogger(requested LogLevel) (*Logger, error) {
@@ -97,39 +97,39 @@ func InitLogger(requested LogLevel) (*Logger, error) {
        case FatalLevel:
                logger, err = initLoggerByLevel(zapcore.FatalLevel)
        default:
-               err = fmt.Errorf("Invalid logging Level :%d",requested)
+               err = fmt.Errorf("invalid logging Level :%d", requested)
        }
        if err != nil {
                return nil, err
        }
-       return &Logger{Logger:logger}, nil
+       return &Logger{Logger: logger}, nil
 
 }
-func(l *Logger)Sync() error {
+func (l *Logger) Sync() error {
        l.Debugf("#logger.Sync - Going to flush buffered log")
        return l.Logger.Sync()
 }
 
-func (l *Logger)Infof(formatMsg string, a ...interface{})  {
+func (l *Logger) Infof(formatMsg string, a ...interface{}) {
        if l.InfoEnabled() {
                msg := fmt.Sprintf(formatMsg, a...)
                l.Logger.Info(msg, zap.Any("mdc", l.getTimeStampMdc()))
        }
 }
 
-func (l *Logger)Debugf(formatMsg string, a ...interface{})  {
-       if l.DebugEnabled(){
+func (l *Logger) Debugf(formatMsg string, a ...interface{}) {
+       if l.DebugEnabled() {
                msg := fmt.Sprintf(formatMsg, a...)
                l.Logger.Debug(msg, zap.Any("mdc", l.getTimeStampMdc()))
        }
 }
 
-func (l *Logger)Errorf(formatMsg string, a ...interface{})  {
+func (l *Logger) Errorf(formatMsg string, a ...interface{}) {
        msg := fmt.Sprintf(formatMsg, a...)
        l.Logger.Error(msg, zap.Any("mdc", l.getTimeStampMdc()))
 }
 
-func (l *Logger)Warnf(formatMsg string, a ...interface{})  {
+func (l *Logger) Warnf(formatMsg string, a ...interface{}) {
        msg := fmt.Sprintf(formatMsg, a...)
        l.Logger.Warn(msg, zap.Any("mdc", l.getTimeStampMdc()))
 }
@@ -140,15 +140,15 @@ func (l *Logger) getTimeStampMdc() map[string]string {
        return mdc
 }
 
-func (l *Logger)InfoEnabled()bool{
+func (l *Logger) InfoEnabled() bool {
        return l.Logger.Core().Enabled(zap.InfoLevel)
 }
 
-func (l *Logger)DebugEnabled()bool{
+func (l *Logger) DebugEnabled() bool {
        return l.Logger.Core().Enabled(zap.DebugLevel)
 }
 
-func (l *Logger)DPanicf(formatMsg string, a ...interface{})  {
+func (l *Logger) DPanicf(formatMsg string, a ...interface{}) {
        msg := fmt.Sprintf(formatMsg, a...)
        l.Logger.DPanic(msg, zap.Any("mdc", l.getTimeStampMdc()))
 }
@@ -184,4 +184,3 @@ func epochMillisIntegerTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncode
        millis := int64(nanos) / int64(time.Millisecond)
        enc.AppendInt64(millis)
 }
-
index d1d00d2..add0262 100644 (file)
@@ -78,9 +78,9 @@ func TestInitInfoLoggerFailure(t *testing.T) {
        assert.Nil(t, log)
 }
 
-func TestSyncSuccess(t *testing.T){
+func TestSyncSuccess(t *testing.T) {
        logFile, err := os.Create("./loggerTest.txt")
-       if err != nil{
+       if err != nil {
                t.Errorf("logger_test.TestSyncSuccess - failed to create file, error: %s", err)
        }
        old := os.Stdout
@@ -94,7 +94,7 @@ func TestSyncSuccess(t *testing.T){
 
        os.Stdout = old
        logFile, err = os.Open("./loggerTest.txt")
-       if err != nil{
+       if err != nil {
                t.Errorf("logger_test.TestSyncSuccess - failed to open file, error: %s", err)
        }
        var buf bytes.Buffer
@@ -102,8 +102,8 @@ func TestSyncSuccess(t *testing.T){
        if err != nil {
                t.Errorf("logger_test.TestSyncSuccess - failed to copy bytes, error: %s", err)
        }
-       debugRecord,_ :=buf.ReadString('\n')
-       errorRecord,_ :=buf.ReadString('\n')
+       debugRecord, _ := buf.ReadString('\n')
+       errorRecord, _ := buf.ReadString('\n')
 
        assert.NotEmpty(t, debugRecord)
        assert.Empty(t, errorRecord)
@@ -114,78 +114,78 @@ func TestSyncSuccess(t *testing.T){
 
 }
 
-func TestSyncFailure(t *testing.T){
+func TestSyncFailure(t *testing.T) {
        log, err := InitLogger(DebugLevel)
        err = log.Sync()
        assert.NotNil(t, err)
 }
 
-func TestDebugEnabledFalse(t *testing.T){
+func TestDebugEnabledFalse(t *testing.T) {
        entryNum, log := countRecords(InfoLevel, t)
        assert.False(t, log.DebugEnabled())
-       assert.Equal(t,3, entryNum)
+       assert.Equal(t, 3, entryNum)
 }
 
-func TestDebugEnabledTrue(t *testing.T){
+func TestDebugEnabledTrue(t *testing.T) {
        entryNum, log := countRecords(DebugLevel, t)
        assert.True(t, log.DebugEnabled())
-       assert.Equal(t,4, entryNum)
+       assert.Equal(t, 4, entryNum)
 }
 
-func TestDPanicfDebugLevel(t *testing.T){
-       assert.True(t,validateRecordExists(DebugLevel, zap.DPanicLevel, t))
+func TestDPanicfDebugLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(DebugLevel, zap.DPanicLevel, t))
 }
 
-func TestDPanicfInfoLevel(t *testing.T){
-       assert.True(t,validateRecordExists(InfoLevel, zap.DPanicLevel, t))
+func TestDPanicfInfoLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(InfoLevel, zap.DPanicLevel, t))
 }
 
-func TestErrorfDebugLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(DebugLevel, zap.ErrorLevel, t))
+func TestErrorfDebugLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(DebugLevel, zap.ErrorLevel, t))
 }
 
-func TestErrorfInfoLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(InfoLevel, zap.ErrorLevel, t))
+func TestErrorfInfoLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(InfoLevel, zap.ErrorLevel, t))
 }
 
-func TestInfofDebugLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(DebugLevel, zap.InfoLevel, t))
+func TestInfofDebugLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(DebugLevel, zap.InfoLevel, t))
 }
 
-func TestInfofInfoLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(InfoLevel, zap.InfoLevel, t))
+func TestInfofInfoLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(InfoLevel, zap.InfoLevel, t))
 }
 
-func TestDebugfDebugLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(DebugLevel, zap.DebugLevel, t))
+func TestDebugfDebugLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(DebugLevel, zap.DebugLevel, t))
 }
 
-func TestDebugfInfoLevel(t *testing.T)  {
-       assert.False(t,validateRecordExists(InfoLevel, zap.DebugLevel, t))
+func TestDebugfInfoLevel(t *testing.T) {
+       assert.False(t, validateRecordExists(InfoLevel, zap.DebugLevel, t))
 }
 
-func TestInfofFatalLevel(t *testing.T)  {
-       assert.False(t,validateRecordExists(FatalLevel, zap.InfoLevel, t))
+func TestInfofFatalLevel(t *testing.T) {
+       assert.False(t, validateRecordExists(FatalLevel, zap.InfoLevel, t))
 }
 
-func TestDebugfFatalLevel(t *testing.T)  {
-       assert.False(t,validateRecordExists(FatalLevel, zap.DebugLevel, t))
+func TestDebugfFatalLevel(t *testing.T) {
+       assert.False(t, validateRecordExists(FatalLevel, zap.DebugLevel, t))
 }
 
-func TestWarnfWarnLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(WarnLevel, zap.WarnLevel, t))
+func TestWarnfWarnLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(WarnLevel, zap.WarnLevel, t))
 }
 
-func TestWarnfDebugLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(DebugLevel, zap.WarnLevel, t))
+func TestWarnfDebugLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(DebugLevel, zap.WarnLevel, t))
 }
 
-func TestWarnfInfoLevel(t *testing.T)  {
-       assert.True(t,validateRecordExists(InfoLevel, zap.WarnLevel, t))
+func TestWarnfInfoLevel(t *testing.T) {
+       assert.True(t, validateRecordExists(InfoLevel, zap.WarnLevel, t))
 }
 
-func TestWarnfFatalLevel(t *testing.T)  {
-       assert.False(t,validateRecordExists(FatalLevel, zap.WarnLevel, t))
+func TestWarnfFatalLevel(t *testing.T) {
+       assert.False(t, validateRecordExists(FatalLevel, zap.WarnLevel, t))
 }
 
 func TestLogLevelTokenToLevel(t *testing.T) {
@@ -222,9 +222,9 @@ func TestLogLevelTokenToLevel(t *testing.T) {
        assert.True(t, level > FatalLevel)
 
 }
-func countRecords(logLevel LogLevel, t *testing.T) (int, *Logger){
+func countRecords(logLevel LogLevel, t *testing.T) (int, *Logger) {
        old := os.Stdout
-       r, w, _ :=os.Pipe()
+       r, w, _ := os.Pipe()
        os.Stdout = w
        log, err := InitLogger(logLevel)
        if err != nil {
@@ -245,24 +245,24 @@ func countRecords(logLevel LogLevel, t *testing.T) (int, *Logger){
                t.Errorf("logger_test.TestSyncFailure - failed to copy bytes, error: %s", err)
        }
        entryNum := 0
-       s,_:= buf.ReadString('\n')
-       for len(s) > 0{
-               entryNum +=1
-               s,_= buf.ReadString('\n')
+       s, _ := buf.ReadString('\n')
+       for len(s) > 0 {
+               entryNum += 1
+               s, _ = buf.ReadString('\n')
        }
        return entryNum, log
 }
 
 func validateRecordExists(logLevel LogLevel, recordLevel zapcore.Level, t *testing.T) bool {
        old := os.Stdout
-       r, w, _ :=os.Pipe()
+       r, w, _ := os.Pipe()
        os.Stdout = w
        log, err := InitLogger(logLevel)
        if err != nil {
                t.Errorf("logger_test.TestSyncFailure - failed to initialize logger, error: %s", err)
        }
-       switch recordLevel{
-       case  zap.DebugLevel:
+       switch recordLevel {
+       case zap.DebugLevel:
                log.Debugf("%v, %v, %v", 1, "abc", 0.1)
        case zap.InfoLevel:
                log.Infof("%v, %v, %v", 1, "abc", 0.1)
@@ -284,10 +284,10 @@ func validateRecordExists(logLevel LogLevel, recordLevel zapcore.Level, t *testi
                t.Errorf("logger_test.TestSyncFailure - failed to copy bytes, error: %s", err)
        }
        entryNum := 0
-       s,_:= buf.ReadString('\n')
-       for len(s) > 0{
-               entryNum +=1
-               s,_= buf.ReadString('\n')
+       s, _ := buf.ReadString('\n')
+       for len(s) > 0 {
+               entryNum += 1
+               s, _ = buf.ReadString('\n')
        }
        return entryNum == 1
-}
\ No newline at end of file
+}
diff --git a/RSM/managers/resource_status_initiate_manager.go b/RSM/managers/resource_status_initiate_manager.go
deleted file mode 100644 (file)
index b96574d..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-package managers
-
-import (
-       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
-       "rsm/e2pdus"
-       "rsm/enums"
-       "rsm/logger"
-       "rsm/models"
-       "rsm/rmrcgo"
-       "rsm/rsmerrors"
-       "rsm/services"
-       "rsm/services/rmrsender"
-)
-
-type ResourceStatusInitiateManager struct {
-       logger          *logger.Logger
-       rnibDataService services.RNibDataService
-       rmrSender       *rmrsender.RmrSender
-}
-
-type IResourceStatusInitiateManager interface {
-       Execute(inventoryName string, resourceStatusInitiateRequestParams *e2pdus.ResourceStatusRequestData) error
-}
-
-func NewResourceStatusInitiateManager(logger *logger.Logger, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender) *ResourceStatusInitiateManager {
-       return &ResourceStatusInitiateManager{
-               logger:          logger,
-               rnibDataService: rnibDataService,
-               rmrSender:       rmrSender,
-       }
-}
-
-func (m *ResourceStatusInitiateManager) Execute(inventoryName string, resourceStatusInitiateRequestParams *e2pdus.ResourceStatusRequestData) error {
-
-       nodebInfo, err := m.rnibDataService.GetNodeb(inventoryName)
-
-       if err != nil {
-               m.logger.Errorf("#ResourceStatusInitiateManager.Execute - RAN name: %s - Error fetching RAN from rNib: %v", inventoryName, err)
-               return rsmerrors.NewRnibDbError()
-       }
-
-       m.logger.Infof("#ResourceStatusInitiateManager.Execute - RAN name: %s, connection status: %s", nodebInfo.GetRanName(), nodebInfo.GetConnectionStatus())
-
-       if nodebInfo.GetConnectionStatus() != entities.ConnectionStatus_CONNECTED {
-               m.logger.Errorf("#ResourceStatusInitiateManager.Execute - RAN name: %s - RAN's connection status isn't CONNECTED", inventoryName)
-               return rsmerrors.NewWrongStateError("Resource Status Initiate", entities.ConnectionStatus_name[int32(nodebInfo.ConnectionStatus)])
-       }
-
-       m.sendResourceStatusInitiatePerCell(nodebInfo, *resourceStatusInitiateRequestParams)
-
-       return nil
-}
-
-func (m *ResourceStatusInitiateManager) sendResourceStatusInitiatePerCell(nodebInfo *entities.NodebInfo, requestParams e2pdus.ResourceStatusRequestData) {
-       enb, _ := nodebInfo.Configuration.(*entities.NodebInfo_Enb)
-       cells := enb.Enb.ServedCells
-
-       for index, cellInfo := range cells {
-               requestParams.CellID = cellInfo.CellId
-               requestParams.MeasurementID = e2pdus.Measurement_ID(index + 1)
-
-               m.logger.Infof("#ResourceStatusInitiateManager.sendResourceStatusInitiatePerCell - RAN name: %s, Going to send request for cell id %s, measurement id %d", nodebInfo.RanName, requestParams.CellID, requestParams.MeasurementID)
-
-               payload, payloadAsString, err := e2pdus.BuildPackedResourceStatusRequest(enums.Registration_Request_start, &requestParams, e2pdus.MaxAsn1PackedBufferSize, e2pdus.MaxAsn1CodecMessageBufferSize, m.logger.DebugEnabled())
-               if err != nil {
-                       m.logger.Errorf("#ResourceStatusInitiateManager.sendResourceStatusInitiatePerCell - RAN name: %s. Failed to build and pack the resource status initiate request for cell id %s, measurement id %d. error: %s", nodebInfo.RanName, requestParams.CellID, requestParams.MeasurementID, err)
-                       continue
-               }
-
-               m.logger.Debugf("#ResourceStatusInitiateManager.sendResourceStatusInitiatePerCell - RAN name: %s, cell id: %s, measurement id: %d, payload: %s", nodebInfo.RanName, requestParams.CellID, requestParams.MeasurementID, payloadAsString)
-
-               rmrMsg := models.NewRmrMessage(rmrcgo.RicResStatusReq, nodebInfo.RanName, payload)
-               go m.rmrSender.Send(rmrMsg)
-       }
-}
diff --git a/RSM/managers/resource_status_initiate_manager_test.go b/RSM/managers/resource_status_initiate_manager_test.go
deleted file mode 100644 (file)
index a8cea62..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-package managers
-
-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"
-       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
-       "github.com/pkg/errors"
-       "github.com/stretchr/testify/assert"
-       "rsm/configuration"
-       "rsm/e2pdus"
-       "rsm/enums"
-       "rsm/logger"
-       "rsm/mocks"
-       "rsm/rmrcgo"
-       "rsm/rsmerrors"
-       "rsm/services"
-       "rsm/tests/testhelper"
-       "testing"
-       "time"
-)
-
-const RanName = "test"
-
-func initResourceStatusInitiateManagerTest(t *testing.T) (*mocks.RmrMessengerMock, *mocks.RnibReaderMock, *e2pdus.ResourceStatusRequestData, *ResourceStatusInitiateManager) {
-       logger, err := logger.InitLogger(logger.InfoLevel)
-       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)
-       }
-
-       rmrMessengerMock := &mocks.RmrMessengerMock{}
-       rmrSender := testhelper.InitRmrSender(rmrMessengerMock, logger)
-
-       readerMock := &mocks.RnibReaderMock{}
-       rnibReaderProvider := func() reader.RNibReader {
-               return readerMock
-       }
-
-       resourceStatusRequestData := &e2pdus.ResourceStatusRequestData{}
-       populateResourceStatusInitiateRequestParams(resourceStatusRequestData, config)
-
-       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider)
-       resourceStatusInitiateManager := NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-       return rmrMessengerMock, readerMock, resourceStatusRequestData, resourceStatusInitiateManager
-}
-
-func TestGetNodebFailure(t *testing.T) {
-       rmrMessengerMock, readerMock, resourceStatusInitiateRequestParams, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       var nodebInfo *entities.NodebInfo
-       readerMock.On("GetNodeb", RanName).Return(nodebInfo, common.NewInternalError(errors.New("Error")))
-       err := resourceStatusInitiateManager.Execute(RanName, resourceStatusInitiateRequestParams)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       assert.IsType(t, &rsmerrors.RnibDbError{}, err)
-       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
-}
-
-func TestInvalidConnectionStatus(t *testing.T) {
-       rmrMessengerMock, readerMock, resourceStatusInitiateRequestParams, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       var err error
-       readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED}, err)
-       err = resourceStatusInitiateManager.Execute(RanName, resourceStatusInitiateRequestParams)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       assert.IsType(t, &rsmerrors.WrongStateError{}, err)
-       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
-}
-
-func TestPackFailure(t *testing.T) {
-       rmrMessengerMock, readerMock, resourceRequestData, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       var err error
-       nodebInfo := &entities.NodebInfo{
-               RanName:          RanName,
-               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
-               Configuration: &entities.NodebInfo_Enb{
-                       Enb: &entities.Enb{
-                               ServedCells: []*entities.ServedCellInfo{{CellId: ""}},
-                       },
-               },
-       }
-
-       readerMock.On("GetNodeb", RanName).Return(nodebInfo, err)
-       err = resourceStatusInitiateManager.Execute(RanName, resourceRequestData)
-       assert.Nil(t, err)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
-}
-
-func TestOneCellSuccess(t *testing.T) {
-       cellId := "02f829:0007ab00"
-       rmrMessengerMock, readerMock, resourceRequestData, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       xaction := []byte(RanName)
-       var err error
-       nodebInfo := &entities.NodebInfo{
-               RanName:          RanName,
-               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
-               Configuration: &entities.NodebInfo_Enb{
-                       Enb: &entities.Enb{
-                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId}},
-                       },
-               },
-       }
-
-       readerMock.On("GetNodeb", RanName).Return(nodebInfo, err)
-       expectedPayload := getPackedPayloadForCell(cellId, 1, *resourceRequestData)
-       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
-       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, err)
-       err = resourceStatusInitiateManager.Execute(RanName, resourceRequestData)
-       time.Sleep(100 * time.Millisecond)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       assert.Nil(t, err)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
-       rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
-}
-
-func TestTwoCellOneFailureOneSuccess(t *testing.T) {
-       cellId1 := "02f829:0007ab00"
-       cellId2 := "02f829:0007ab50"
-       rmrMessengerMock, readerMock, resourceRequestData, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       xaction := []byte(RanName)
-       var err error
-       nodebInfo := &entities.NodebInfo{
-               RanName:          RanName,
-               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
-               Configuration: &entities.NodebInfo_Enb{
-                       Enb: &entities.Enb{
-                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}},
-                       },
-               },
-       }
-
-       readerMock.On("GetNodeb", RanName).Return(nodebInfo, err)
-       expectedPayload1 := getPackedPayloadForCell(cellId1, 1, *resourceRequestData)
-       expectedMbuf1 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload1), RanName, &expectedPayload1, &xaction)
-
-       expectedPayload2 := getPackedPayloadForCell(cellId2, 2, *resourceRequestData)
-       expectedMbuf2 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload2), RanName, &expectedPayload2, &xaction)
-       rmrMessengerMock.On("SendMsg", expectedMbuf1).Return(&rmrcgo.MBuf{}, rsmerrors.NewRmrError())
-       rmrMessengerMock.On("SendMsg", expectedMbuf2).Return(&rmrcgo.MBuf{}, err)
-       err = resourceStatusInitiateManager.Execute(RanName, resourceRequestData)
-       time.Sleep(100 * time.Millisecond)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       assert.Nil(t, err)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf1)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf2)
-       rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 2)
-}
-
-func TestFiveCellsSuccess(t *testing.T) {
-       cellId1 := "02f829:0007ab00"
-       cellId2 := "02f829:0007ab50"
-       cellId3 := "02f829:0007ab60"
-       cellId4 := "02f829:0007ab70"
-       cellId5 := "02f829:0007ab80"
-
-       rmrMessengerMock, readerMock, resourceRequestData, resourceStatusInitiateManager := initResourceStatusInitiateManagerTest(t)
-       xaction := []byte(RanName)
-       var err error
-       nodebInfo := &entities.NodebInfo{
-               RanName:          RanName,
-               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
-               Configuration: &entities.NodebInfo_Enb{
-                       Enb: &entities.Enb{
-                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}, {CellId: cellId3}, {CellId: cellId4}, {CellId: cellId5}},
-                       },
-               },
-       }
-
-       readerMock.On("GetNodeb", RanName).Return(nodebInfo, err)
-       expectedPayload1 := getPackedPayloadForCell(cellId1, 1, *resourceRequestData)
-       expectedMbuf1 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload1), RanName, &expectedPayload1, &xaction)
-
-       expectedPayload2 := getPackedPayloadForCell(cellId2, 2, *resourceRequestData)
-       expectedMbuf2 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload2), RanName, &expectedPayload2, &xaction)
-
-       expectedPayload3 := getPackedPayloadForCell(cellId3, 3, *resourceRequestData)
-       expectedMbuf3 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload3), RanName, &expectedPayload3, &xaction)
-
-       expectedPayload4 := getPackedPayloadForCell(cellId4, 4, *resourceRequestData)
-       expectedMbuf4 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload4), RanName, &expectedPayload4, &xaction)
-
-       expectedPayload5 := getPackedPayloadForCell(cellId5, 5, *resourceRequestData)
-       expectedMbuf5 := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload5), RanName, &expectedPayload5, &xaction)
-
-       rmrMessengerMock.On("SendMsg", expectedMbuf1).Return(&rmrcgo.MBuf{}, err)
-       rmrMessengerMock.On("SendMsg", expectedMbuf2).Return(&rmrcgo.MBuf{}, err)
-       rmrMessengerMock.On("SendMsg", expectedMbuf3).Return(&rmrcgo.MBuf{}, err)
-       rmrMessengerMock.On("SendMsg", expectedMbuf4).Return(&rmrcgo.MBuf{}, err)
-       rmrMessengerMock.On("SendMsg", expectedMbuf5).Return(&rmrcgo.MBuf{}, err)
-
-       err = resourceStatusInitiateManager.Execute(RanName, resourceRequestData)
-       time.Sleep(100 * time.Millisecond)
-       readerMock.AssertCalled(t, "GetNodeb", RanName)
-       assert.Nil(t, err)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf1)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf2)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf3)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf4)
-       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf5)
-
-       rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 5)
-}
-
-func getPackedPayloadForCell(cellId string, index int, resourceStatusRequestData e2pdus.ResourceStatusRequestData) []byte {
-       resourceStatusRequestData.CellID = cellId
-       resourceStatusRequestData.MeasurementID = e2pdus.Measurement_ID(index)
-       expectedPayload, _, _ := e2pdus.BuildPackedResourceStatusRequest(enums.Registration_Request_start, &resourceStatusRequestData, e2pdus.MaxAsn1PackedBufferSize, e2pdus.MaxAsn1CodecMessageBufferSize, false)
-       return expectedPayload
-}
-
-func populateResourceStatusInitiateRequestParams(params *e2pdus.ResourceStatusRequestData, config *configuration.Configuration) {
-       params.PartialSuccessAllowed = config.ResourceStatusParams.PartialSuccessAllowed
-       params.PrbPeriodic = config.ResourceStatusParams.PrbPeriodic
-       params.TnlLoadIndPeriodic = config.ResourceStatusParams.TnlLoadIndPeriodic
-       params.HwLoadIndPeriodic = config.ResourceStatusParams.HwLoadIndPeriodic
-       params.AbsStatusPeriodic = config.ResourceStatusParams.AbsStatusPeriodic
-       params.RsrpMeasurementPeriodic = config.ResourceStatusParams.RsrpMeasurementPeriodic
-       params.CsiPeriodic = config.ResourceStatusParams.CsiPeriodic
-       params.PeriodicityMS = config.ResourceStatusParams.PeriodicityMs
-       params.PeriodicityRsrpMeasurementMS = config.ResourceStatusParams.PeriodicityRsrpMeasurementMs
-       params.PeriodicityCsiMS = config.ResourceStatusParams.PeriodicityCsiMs
-}
index 9a13f0a..a5cb59e 100644 (file)
@@ -24,7 +24,6 @@ import (
        "rsm/configuration"
        "rsm/converters"
        "rsm/logger"
-       "rsm/managers"
        "rsm/models"
        "rsm/providers/rmrmsghandlerprovider"
        "rsm/rmrcgo"
@@ -38,12 +37,12 @@ type RmrMessageManager struct {
        handlerProvider *rmrmsghandlerprovider.MessageHandlerProvider
 }
 
-func NewRmrMessageManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, unpacker converters.Asn1PduUnpacker) *RmrMessageManager {
-       handlerProvider := rmrmsghandlerprovider.NewMessageHandlerProvider(logger,config, rnibDataService, rmrSender, resourceStatusInitiateManager, unpacker)
+func NewRmrMessageManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusService *services.ResourceStatusService, rsConverter converters.ResourceStatusResponseConverter, rsFailureConverter converters.ResourceStatusFailureConverter) *RmrMessageManager {
+       handlerProvider := rmrmsghandlerprovider.NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusService, rsConverter, rsFailureConverter)
 
        return &RmrMessageManager{
                handlerProvider: handlerProvider,
-               logger: logger,
+               logger:          logger,
        }
 }
 
index 5184e62..56aa30d 100644 (file)
@@ -21,8 +21,10 @@ package rmrmanagers
 
 import (
        "rsm/configuration"
-       "rsm/managers"
+       "rsm/converters"
+       "rsm/e2pdus"
        "rsm/rmrcgo"
+       "rsm/services"
        "rsm/tests/testhelper"
        "testing"
 )
@@ -31,9 +33,9 @@ func TestRmrMessageManagerSuccess(t *testing.T) {
 
        rnibDataService, rmrSender, logger := testhelper.InitTestCase(t)
        config, _ := configuration.ParseConfiguration()
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-
-       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        xactionByteArr := []byte("1111111")
        payloadByteArr := []byte("payload")
@@ -46,9 +48,9 @@ func TestRmrMessageManagerFailure(t *testing.T) {
 
        rnibDataService, rmrSender, logger := testhelper.InitTestCase(t)
        config, _ := configuration.ParseConfiguration()
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-
-       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        xactionByteArr := []byte("1111111")
        payloadByteArr := []byte("payload")
index 6a66569..36cf4a6 100644 (file)
@@ -1,9 +1,34 @@
+//
+// 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 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/mocks/resource_status_failure_converter_mock.go b/RSM/mocks/resource_status_failure_converter_mock.go
new file mode 100644 (file)
index 0000000..2722ffe
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// 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 mocks
+
+import (
+       "github.com/stretchr/testify/mock"
+       "rsm/models"
+)
+
+type ResourceStatusFailureConverterMock struct {
+       mock.Mock
+}
+
+func (m *ResourceStatusFailureConverterMock) Convert(packedBuf []byte) (*models.ResourceStatusResponse, error) {
+       args := m.Called(packedBuf)
+       return args.Get(0).(*models.ResourceStatusResponse), args.Error(1)
+}
+
+func (m *ResourceStatusFailureConverterMock) UnpackX2apPduAsString(packedBuf []byte, maxMessageBufferSize int) (string, error) {
+       args := m.Called(packedBuf, maxMessageBufferSize)
+       return args.Get(0).(string), args.Error(1)
+}
diff --git a/RSM/mocks/resource_status_initiate_manager_mock.go b/RSM/mocks/resource_status_initiate_manager_mock.go
deleted file mode 100644 (file)
index 9251f60..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package mocks
-
-import (
-       "github.com/stretchr/testify/mock"
-       "rsm/e2pdus"
-)
-
-type ResourceStatusInitiateManagerMock struct {
-       mock.Mock
-}
-
-func (m *ResourceStatusInitiateManagerMock) Execute(inventoryName string, resourceStatusInitiateRequestParams *e2pdus.ResourceStatusRequestData) error {
-       args := m.Called(inventoryName, resourceStatusInitiateRequestParams)
-       return args.Error(0)
-}
diff --git a/RSM/mocks/resource_status_response_converter_mock.go b/RSM/mocks/resource_status_response_converter_mock.go
new file mode 100644 (file)
index 0000000..674d244
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// 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 mocks
+
+import (
+       "github.com/stretchr/testify/mock"
+       "rsm/models"
+)
+
+type ResourceStatusResponseConverterMock struct {
+       mock.Mock
+}
+
+func (m *ResourceStatusResponseConverterMock) Convert(packedBuf []byte) (*models.ResourceStatusResponse, error) {
+       args := m.Called(packedBuf)
+       return args.Get(0).(*models.ResourceStatusResponse), args.Error(1)
+}
+
+func (m *ResourceStatusResponseConverterMock) UnpackX2apPduAsString(packedBuf []byte, maxMessageBufferSize int) (string, error) {
+       args := m.Called(packedBuf, maxMessageBufferSize)
+       return args.Get(0).(string), args.Error(1)
+}
diff --git a/RSM/mocks/resource_status_service_mock.go b/RSM/mocks/resource_status_service_mock.go
new file mode 100644 (file)
index 0000000..f7ff2be
--- /dev/null
@@ -0,0 +1,38 @@
+//
+// 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 mocks
+
+import (
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
+       "github.com/stretchr/testify/mock"
+       "rsm/models"
+)
+
+type ResourceStatusServiceMock struct {
+       mock.Mock
+}
+
+func (m *ResourceStatusServiceMock) BuildAndSendInitiateRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64) error {
+       args := m.Called(nodeb, config, enb1MeasurementId)
+       return args.Error(0)
+}
+
+func (m *ResourceStatusServiceMock) BuildAndSendStopRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64, enb2MeasurementId int64) error {
+       args := m.Called(nodeb, config, enb1MeasurementId, enb2MeasurementId)
+       return args.Error(0)
+}
\ No newline at end of file
index 9cc4670..e9b4f1a 100644 (file)
@@ -30,34 +30,34 @@ type RmrMessengerMock struct {
        mock.Mock
 }
 
-func (m *RmrMessengerMock) Init(readyIntervalSec int, port string, maxMsgSize int, flags int, logger *logger.Logger) rmrcgo.RmrMessenger{
+func (m *RmrMessengerMock) Init(readyIntervalSec int, port string, maxMsgSize int, flags int, logger *logger.Logger) rmrcgo.RmrMessenger {
        args := m.Called(readyIntervalSec, port, maxMsgSize, flags, logger)
        return args.Get(0).(rmrcgo.RmrMessenger)
 }
 
-func (m *RmrMessengerMock) SendMsg(msg *rmrcgo.MBuf) (*rmrcgo.MBuf, error){
+func (m *RmrMessengerMock) SendMsg(msg *rmrcgo.MBuf) (*rmrcgo.MBuf, error) {
        args := m.Called(msg)
        return args.Get(0).(*rmrcgo.MBuf), args.Error(1)
 }
 
-func (m *RmrMessengerMock) RecvMsg() (*rmrcgo.MBuf, error){
-       args := m.Called( )
+func (m *RmrMessengerMock) RecvMsg() (*rmrcgo.MBuf, error) {
+       args := m.Called()
        return args.Get(0).(*rmrcgo.MBuf), args.Error(1)
 }
 
-func (m *RmrMessengerMock) RtsMsg(msg *rmrcgo.MBuf){
-       m.Called( )
+func (m *RmrMessengerMock) RtsMsg(msg *rmrcgo.MBuf) {
+       m.Called()
 }
 
-func (m *RmrMessengerMock) FreeMsg(){
-       m.Called( )
+func (m *RmrMessengerMock) FreeMsg() {
+       m.Called()
 }
 
-func (m *RmrMessengerMock) IsReady() bool{
-       args := m.Called( )
+func (m *RmrMessengerMock) IsReady() bool {
+       args := m.Called()
        return args.Bool(0)
 }
 
-func (m *RmrMessengerMock) Close(){
-       m.Called( )
-}
\ No newline at end of file
+func (m *RmrMessengerMock) Close() {
+       m.Called()
+}
index 5ed6045..3d2fff9 100644 (file)
@@ -149,3 +149,18 @@ func (m *RnibReaderMock) GetRanLoadInformation(inventoryName string) (*entities.
 
        return args.Get(0).(*entities.RanLoadInformation), nil
 }
+
+func (m *RnibReaderMock) GetE2TInstance(e2taddress string) (*entities.E2TInstance, error) {
+       args := m.Called(e2taddress)
+       return args.Get(0).(*entities.E2TInstance), args.Error(1)
+}
+
+func (m *RnibReaderMock) GetE2TInstances(addresses []string) ([]*entities.E2TInstance, error) {
+       args := m.Called(addresses)
+       return args.Get(0).([]*entities.E2TInstance), args.Error(1)
+}
+
+func (m *RnibReaderMock) GetE2TAddresses() ([]string, error) {
+       args := m.Called()
+       return args.Get(0).([]string), args.Error(1)
+}
index bc304c1..46bd86f 100644 (file)
@@ -1,3 +1,20 @@
+//
+// 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 mocks
 
 import (
diff --git a/RSM/mocks/rsm_reader_mock.go b/RSM/mocks/rsm_reader_mock.go
new file mode 100644 (file)
index 0000000..4ade9cd
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// 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 mocks
+
+import (
+       "github.com/stretchr/testify/mock"
+       "rsm/models"
+)
+
+type RsmReaderMock struct {
+       mock.Mock
+}
+
+func (m *RsmReaderMock) GetRsmRanInfo(inventoryName string) (*models.RsmRanInfo, error) {
+       args := m.Called(inventoryName)
+       return args.Get(0).(*models.RsmRanInfo), args.Error(1)
+}
+
+func (m *RsmReaderMock) GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) {
+       args := m.Called()
+       return args.Get(0).(*models.RsmGeneralConfiguration), args.Error(1)
+}
similarity index 71%
rename from RSM/mocks/unpacker_mock.go
rename to RSM/mocks/rsm_writer_mock.go
index 717a18d..aec981c 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright 2019 AT&T Intellectual Property
 // Copyright 2019 Nokia
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
+// 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
 //
 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
 //  platform project (RICP).
 
-
 package mocks
 
 import (
        "github.com/stretchr/testify/mock"
+       "rsm/models"
 )
 
-type Asn1PduUnpackerMock struct {
+type RsmWriterMock struct {
        mock.Mock
 }
 
-func (m *Asn1PduUnpackerMock)UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error){
-       args := m.Called(packedBufferSize, packedBuf, maxMessageBufferSize)
-       return args.Get(0).(string), args.Error(1)
+func (m *RsmWriterMock) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error {
+       args := m.Called(rsmRanInfo)
+       return args.Error(0)
 }
 
-
+func (m *RsmWriterMock) SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error {
+       args := m.Called(cfg)
+       return args.Error(0)
+}
index 00eea6b..efeb5e0 100644 (file)
@@ -109,7 +109,7 @@ func (m *MockSdlInstance) RemoveIf(key string, data interface{}) (bool, error) {
        return a.Bool(0), a.Error(1)
 }
 
-func (m *MockSdlInstance) AddMember(group string, member ...interface{}) error{
+func (m *MockSdlInstance) AddMember(group string, member ...interface{}) error {
        a := m.Called(group, member)
        return a.Error(0)
 }
@@ -126,11 +126,11 @@ func (m *MockSdlInstance) GetMembers(group string) ([]string, error) {
        a := m.Called(group)
        return a.Get(0).([]string), a.Error(1)
 }
-func (m *MockSdlInstance) IsMember(group string, member interface{}) (bool, error){
+func (m *MockSdlInstance) IsMember(group string, member interface{}) (bool, error) {
        a := m.Called(group, member)
        return a.Bool(0), a.Error(1)
 }
-func (m *MockSdlInstance) GroupSize(group string) (int64, error){
-       a := m.Called(group,)
+func (m *MockSdlInstance) GroupSize(group string) (int64, error) {
+       a := m.Called(group)
        return int64(a.Int(0)), a.Error(1)
 }
index 951a95f..2cffd1b 100644 (file)
@@ -21,5 +21,4 @@
 package models
 
 type Request interface {
-
 }
index 5e5c1c9..bca52dc 100644 (file)
@@ -1,8 +1,25 @@
+//
+// 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
 
 import (
-       "rsm/enums"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
+       "rsm/enums"
 )
 
 type ResourceStatusPayload struct {
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"`
+}
diff --git a/RSM/models/resource_status_response.go b/RSM/models/resource_status_response.go
new file mode 100644 (file)
index 0000000..dae459e
--- /dev/null
@@ -0,0 +1,64 @@
+//
+// 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
+
+import (
+       "fmt"
+       "strings"
+)
+
+type MeasurementFailureCause struct {
+       MeasurementFailedReportCharacteristics []byte
+}
+
+func (r MeasurementFailureCause) String() string {
+       return fmt.Sprintf("MeasurementFailedReportCharacteristics: %x", r.MeasurementFailedReportCharacteristics)
+}
+
+type MeasurementInitiationResult struct {
+       CellId                   string
+       MeasurementFailureCauses []*MeasurementFailureCause
+}
+
+func (r MeasurementInitiationResult) String() string {
+       var strBuilder strings.Builder
+       strBuilder.WriteString("[ ")
+       for _, cause := range r.MeasurementFailureCauses {
+               strBuilder.WriteString(cause.String())
+               strBuilder.WriteString(" ")
+       }
+       strBuilder.WriteString(" ]")
+       return fmt.Sprintf("CellId: %s, MeasurementFailureCauses: %s", r.CellId, strBuilder.String())
+}
+
+type ResourceStatusResponse struct {
+       ENB1_Measurement_ID          int64
+       ENB2_Measurement_ID          int64
+       MeasurementInitiationResults []*MeasurementInitiationResult
+}
+
+func (r ResourceStatusResponse) String() string {
+       var strBuilder strings.Builder
+       strBuilder.WriteString("[ ")
+       for _, result := range r.MeasurementInitiationResults {
+               strBuilder.WriteString(result.String())
+               strBuilder.WriteString(" ")
+       }
+       strBuilder.WriteString(" ]")
+       return fmt.Sprintf("ENB1_Measurement_ID: %d, ENB2_Measurement_ID: %d, MeasurementInitiationResults:%s", r.ENB1_Measurement_ID, r.ENB2_Measurement_ID, strBuilder.String())
+}
index 62cbfe2..531fbbd 100644 (file)
@@ -22,4 +22,4 @@ package models
 
 type IResponse interface {
        Marshal() (string, error)
-}
\ No newline at end of file
+}
index fb26bf0..4f136c9 100644 (file)
@@ -40,4 +40,4 @@ func NewRmrMessage(msgType int, ranName string, payload []byte) *RmrMessage {
 
 func (response RmrMessage) GetMessageAsBytes(logger *logger.Logger) []byte {
        return response.Payload
-}
\ No newline at end of file
+}
index 459d5ec..43d6f09 100644 (file)
@@ -23,10 +23,10 @@ package models
 import "time"
 
 type RmrRequest struct {
-       RanName       string
-       Len           int
-       Payload       []byte
-       StartTime     time.Time
+       RanName   string
+       Len       int
+       Payload   []byte
+       StartTime time.Time
 }
 
 func NewRmrRequest(ranName string, payload []byte, startTime time.Time) *RmrRequest {
@@ -36,4 +36,4 @@ func NewRmrRequest(ranName string, payload []byte, startTime time.Time) *RmrRequ
                payload,
                startTime,
        }
-}
\ No newline at end of file
+}
diff --git a/RSM/models/rsm_general_configuration.go b/RSM/models/rsm_general_configuration.go
new file mode 100644 (file)
index 0000000..d892d81
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// 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
+
+import "rsm/enums"
+
+type RsmGeneralConfiguration struct {
+       EnableResourceStatus         bool                             `json:"enableResourceStatus"`
+       PartialSuccessAllowed        bool                             `json:"partialSuccessAllowed"`
+       PrbPeriodic                  bool                             `json:"prbPeriodic"`
+       TnlLoadIndPeriodic           bool                             `json:"tnlLoadIndPeriodic"`
+       HwLoadIndPeriodic            bool                             `json:"wwLoadIndPeriodic"`
+       AbsStatusPeriodic            bool                             `json:"absStatusPeriodic"`
+       RsrpMeasurementPeriodic      bool                             `json:"rsrpMeasurementPeriodic"`
+       CsiPeriodic                  bool                             `json:"csiPeriodic"`
+       PeriodicityMs                enums.ReportingPeriodicity       `json:"periodicityMs"`
+       PeriodicityRsrpMeasurementMs enums.ReportingPeriodicityRSRPMR `json:"periodicityRsrpMeasurementMs"`
+       PeriodicityCsiMs             enums.ReportingPeriodicityCSIR   `json:"periodicityCsiMs"`
+}
diff --git a/RSM/models/rsm_ran_info.go b/RSM/models/rsm_ran_info.go
new file mode 100644 (file)
index 0000000..b67b983
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// 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
+
+import (
+       "rsm/enums"
+)
+
+type RsmRanInfo struct {
+       RanName           string          `json:"ranName"`
+       Enb1MeasurementId int64           `json:"enb1MeasurementId"`
+       Enb2MeasurementId int64           `json:"enb2MeasurementId"`
+       Action            enums.RsmAction `json:"action"`
+       ActionStatus      bool            `json:"actionStatus"`
+}
+
+func NewRsmRanInfo(ranName string, enb1MeasurementId int64, enb2MeasurementId int64, action enums.RsmAction, actionStatus bool) *RsmRanInfo {
+       return &RsmRanInfo{
+               RanName:           ranName,
+               Enb1MeasurementId: enb1MeasurementId,
+               Enb2MeasurementId: enb2MeasurementId,
+               Action:            action,
+               ActionStatus:      actionStatus,
+       }
+}
index 900cfef..5d22aaa 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 {
@@ -62,4 +61,4 @@ func (provider RequestHandlerProvider) GetHandler(requestType IncomingRequest) (
        }
 
        return handler, nil
-}
+}
\ No newline at end of file
index b51fa51..58572ca 100644 (file)
@@ -24,18 +24,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) {
@@ -44,6 +58,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)
 
index d65db4d..e92e78f 100644 (file)
@@ -27,7 +27,6 @@ import (
        "rsm/converters"
        "rsm/handlers/rmrmsghandlers"
        "rsm/logger"
-       "rsm/managers"
        "rsm/rmrcgo"
        "rsm/services"
        "rsm/services/rmrsender"
@@ -42,18 +41,18 @@ type MessageHandlerProvider struct {
        msgHandlers map[int]rmrmsghandlers.RmrMessageHandler
 }
 
-func NewMessageHandlerProvider(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, unpacker converters.Asn1PduUnpacker) *MessageHandlerProvider {
+func NewMessageHandlerProvider(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusService *services.ResourceStatusService, rsConverter converters.ResourceStatusResponseConverter, rsFailureConverter converters.ResourceStatusFailureConverter) *MessageHandlerProvider {
        return &MessageHandlerProvider{
-               msgHandlers: initMessageHandlersMap(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, unpacker),
+               msgHandlers: initMessageHandlersMap(logger, config, rnibDataService, rmrSender, resourceStatusService, rsConverter, rsFailureConverter),
        }
 }
 
-func initMessageHandlersMap(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, unpacker converters.Asn1PduUnpacker) map[int]rmrmsghandlers.RmrMessageHandler {
+func initMessageHandlersMap(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, resourceStatusService *services.ResourceStatusService, rsConverter converters.ResourceStatusResponseConverter, rsFailureConverter converters.ResourceStatusFailureConverter) map[int]rmrmsghandlers.RmrMessageHandler {
        return map[int]rmrmsghandlers.RmrMessageHandler{
-               rmrcgo.RanConnected:        rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, config, resourceStatusInitiateManager, RanConnected),
-               rmrcgo.RanRestarted:        rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, config, resourceStatusInitiateManager, RanRestarted),
-               rmrcgo.RicResStatusFailure: rmrmsghandlers.NewResourceStatusFailureHandler(logger, unpacker),
-               rmrcgo.RicResStatusResp:    rmrmsghandlers.NewResourceStatusResponseHandler(logger),
+               rmrcgo.RanConnected:        rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, rnibDataService, resourceStatusService, RanConnected),
+               rmrcgo.RanRestarted:        rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, rnibDataService, resourceStatusService, RanRestarted),
+               rmrcgo.RicResStatusFailure: rmrmsghandlers.NewResourceStatusFailureHandler(logger, rsFailureConverter),
+               rmrcgo.RicResStatusResp:    rmrmsghandlers.NewResourceStatusResponseHandler(logger, rsConverter, rnibDataService),
        }
 }
 
@@ -61,7 +60,7 @@ func (provider MessageHandlerProvider) GetMessageHandler(messageType int) (rmrms
        handler, ok := provider.msgHandlers[messageType]
 
        if !ok {
-               msg := fmt.Sprintf("#MessageHandlerProvider.GetMessageHandler - notification handler not found for message %d",messageType )
+               msg := fmt.Sprintf("#MessageHandlerProvider.GetMessageHandler - notification handler not found for message %d", messageType)
                return nil, errors.New(msg)
        }
 
index a43f641..fadcd5c 100644 (file)
@@ -23,8 +23,10 @@ package rmrmsghandlerprovider
 import (
        "fmt"
        "rsm/configuration"
+       "rsm/converters"
+       "rsm/e2pdus"
        "rsm/handlers/rmrmsghandlers"
-       "rsm/managers"
+       "rsm/services"
        "rsm/tests/testhelper"
        "strings"
        "testing"
@@ -42,18 +44,18 @@ func TestGetNotificationHandlerSuccess(t *testing.T) {
        if err != nil {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
        var testCases = []struct {
                msgType int
                handler rmrmsghandlers.RmrMessageHandler
        }{
-               {rmrcgo.RanConnected, rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, config, resourceStatusInitiateManager, RanConnected)},
-               {rmrcgo.RanRestarted, rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, config, resourceStatusInitiateManager, RanRestarted)},
+               {rmrcgo.RanConnected, rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, rnibDataService, resourceStatusService, RanConnected)},
+               {rmrcgo.RanRestarted, rmrmsghandlers.NewResourceStatusInitiateNotificationHandler(logger, rnibDataService, resourceStatusService, RanRestarted)},
        }
 
        for _, tc := range testCases {
-               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
                t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) {
                        handler, err := provider.GetMessageHandler(tc.msgType)
                        if err != nil {
@@ -77,7 +79,8 @@ func TestGetNotificationHandlerFailure(t *testing.T) {
        if err != nil {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
 
        var testCases = []struct {
                msgType   int
@@ -86,7 +89,7 @@ func TestGetNotificationHandlerFailure(t *testing.T) {
                {9999 /*unknown*/, "notification handler not found"},
        }
        for _, tc := range testCases {
-               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
                t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) {
                        _, err := provider.GetMessageHandler(tc.msgType)
                        if err == nil {
index 700ebc7..a2bd2db 100644 (file)
@@ -8,16 +8,4 @@ rmr:
   readyIntervalSec: 1
 rnib:
   maxRnibConnectionAttempts: 3
-  rnibRetryIntervalMs: 10
-resourceStatusParams:
-  enableResourceStatus: true
-  partialSuccessAllowed: true
-  prbPeriodic: true
-  tnlLoadIndPeriodic: true
-  hwLoadIndPeriodic: true
-  absStatusPeriodic: true
-  rsrpMeasurementPeriodic: true
-  csiPeriodic: true
-  periodicityMs: 1000
-  periodicityRsrpMeasurementMs: 480
-  periodicityCsiMs: 20
+  rnibRetryIntervalMs: 10
\ No newline at end of file
index ef59387..426bea3 100644 (file)
@@ -29,7 +29,6 @@ import (
        "rsm/tests"
        "strconv"
        "testing"
-       "time"
 )
 
 var (
@@ -55,28 +54,12 @@ func TestNewMBufSuccess(t *testing.T) {
        assert.Equal(t, msg.Meid, "RanName")
        assert.Equal(t, msg.Len, len(tests.DummyPayload))
 }
-//TODO check why test failure and TestIsReadySuccess success
-func TestInitFailure(t *testing.T) {
-       log := initLog(t)
-       go initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
-       time.Sleep(time.Second)
-       if msgr != nil {
-               t.Errorf("The rmr router is ready, should be not ready")
-       }
-}
-
-func TestIsReadyFailure(t *testing.T) {
-       log := initLog(t)
-       go initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
-       assert.True(t, msgr == nil || !msgr.IsReady())
-}
 
 func TestSendRecvMsgSuccess(t *testing.T) {
        log := initLog(t)
 
-       go initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
-       time.Sleep(time.Duration(2) * time.Second)
-       if msgr == nil || !msgr.IsReady()  {
+       initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
+       if msgr == nil || !msgr.IsReady() {
                t.Errorf("#rmr_c_go_api_test.TestSendRecvMsgSuccess - The rmr router is not ready")
        }
 
@@ -97,9 +80,8 @@ func TestSendRecvMsgSuccess(t *testing.T) {
 func TestSendMsgRmrInvalidPortError(t *testing.T) {
        log := initLog(t)
 
-       go initRmr(tests.ReadyIntervalSec, "tcp:" + strconv.Itoa(5555), tests.MaxMsgSize, tests.Flags, log)
-       time.Sleep(time.Duration(2) * time.Second)
-       if msgr == nil || !msgr.IsReady()  {
+       initRmr(tests.ReadyIntervalSec, "tcp:"+strconv.Itoa(5555), tests.MaxMsgSize, tests.Flags, log)
+       if msgr == nil || !msgr.IsReady() {
                t.Errorf("#rmr_c_go_api_test.TestSendMsgRmrInvalidPortError - The rmr router is not ready")
        }
 
@@ -116,9 +98,8 @@ func TestSendMsgRmrInvalidPortError(t *testing.T) {
 func TestSendMsgRmrInvalidMsgNumError(t *testing.T) {
        log := initLog(t)
 
-       go initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
-       time.Sleep(time.Duration(2) * time.Second)
-       if msgr == nil || !msgr.IsReady()  {
+       initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
+       if msgr == nil || !msgr.IsReady() {
                t.Errorf("#rmr_c_go_api_test.TestSendMsgRmrInvalidMsgNumError - The rmr router is not ready")
        }
 
@@ -135,14 +116,15 @@ func TestSendMsgRmrInvalidMsgNumError(t *testing.T) {
 func TestIsReadySuccess(t *testing.T) {
        log := initLog(t)
 
-       go initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
-       time.Sleep(time.Duration(tests.ReadyIntervalSec))
-       if msgr == nil || !msgr.IsReady()  {
+       initRmr(tests.ReadyIntervalSec, tests.GetPort(), tests.MaxMsgSize, tests.Flags, log)
+       if msgr == nil || !msgr.IsReady() {
                t.Errorf("#rmr_c_go_api_test.TestIsReadySuccess - The rmr router is not ready")
        }
+
+       msgr.Close()
 }
 
-func initRmr(readyIntervalSec int, port string, maxMsgSize int, flags int, log *logger.Logger){
+func initRmr(readyIntervalSec int, port string, maxMsgSize int, flags int, log *logger.Logger) {
        var ctx *Context
        msgr = ctx.Init(readyIntervalSec, port, maxMsgSize, flags, log)
 }
@@ -153,4 +135,4 @@ func initLog(t *testing.T) *logger.Logger {
                t.Errorf("#rmr_c_go_api_test.initLog - failed to initialize logger, error: %s", err)
        }
        return log
-}
\ No newline at end of file
+}
index 7595ed1..edf86d5 100644 (file)
@@ -33,23 +33,23 @@ import (
 )
 
 func convertToMBuf(m *C.rmr_mbuf_t) *MBuf {
-       payloadArr := C.GoBytes(unsafe.Pointer(m.payload),C.int(m.len))
-       xActionArr := C.GoBytes(unsafe.Pointer(m.xaction),C.int(RMR_MAX_XACTION_LEN))
+       payloadArr := C.GoBytes(unsafe.Pointer(m.payload), C.int(m.len))
+       xActionArr := C.GoBytes(unsafe.Pointer(m.xaction), C.int(RMR_MAX_XACTION_LEN))
 
        // Trim padding (space and 0)
-       xActionStr :=  strings.TrimRight(string(xActionArr),"\040\000")
+       xActionStr := strings.TrimRight(string(xActionArr), "\040\000")
        xActionArr = []byte(xActionStr)
 
        mbuf := &MBuf{
-               MType: int(m.mtype),
-               Len:   int(m.len),
+               MType:   int(m.mtype),
+               Len:     int(m.len),
                Payload: &payloadArr,
                XAction: &xActionArr,
        }
 
        meidBuf := make([]byte, RMR_MAX_MEID_LEN)
        if meidCstr := C.rmr_get_meid(m, (*C.uchar)(unsafe.Pointer(&meidBuf[0]))); meidCstr != nil {
-               mbuf.Meid =     strings.TrimRight(string(meidBuf), "\000")
+               mbuf.Meid = strings.TrimRight(string(meidBuf), "\000")
        }
 
        return mbuf
@@ -57,7 +57,7 @@ func convertToMBuf(m *C.rmr_mbuf_t) *MBuf {
 
 func (ctx *Context) getAllocatedCRmrMBuf(logger *logger.Logger, mBuf *MBuf, maxMsgSize int) (cMBuf *C.rmr_mbuf_t) {
        var xActionBuf [RMR_MAX_XACTION_LEN]byte
-       var meidBuf[RMR_MAX_MEID_LEN]byte
+       var meidBuf [RMR_MAX_MEID_LEN]byte
 
        cMBuf = C.rmr_alloc_msg(ctx.RmrCtx, C.int(maxMsgSize))
        cMBuf.mtype = C.int(mBuf.MType)
@@ -68,13 +68,13 @@ func (ctx *Context) getAllocatedCRmrMBuf(logger *logger.Logger, mBuf *MBuf, maxM
 
        //Add padding
        copy(xActionBuf[:], *mBuf.XAction)
-       for i:= xActionLen; i < RMR_MAX_XACTION_LEN; i++{
+       for i := xActionLen; i < RMR_MAX_XACTION_LEN; i++ {
                xActionBuf[i] = '\040' //space
        }
 
        // Add padding
        copy(meidBuf[:], mBuf.Meid)
-       for i:= len(mBuf.Meid); i < RMR_MAX_MEID_LEN; i++{
+       for i := len(mBuf.Meid); i < RMR_MAX_MEID_LEN; i++ {
                meidBuf[i] = 0
        }
 
@@ -91,7 +91,7 @@ func (ctx *Context) getAllocatedCRmrMBuf(logger *logger.Logger, mBuf *MBuf, maxM
                ctx.Logger.Errorf(
                        "#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to read xAction data to allocated RMR message buffer")
        }
-       len := C.rmr_bytes2meid(cMBuf,  (*C.uchar)(unsafe.Pointer(&meidBuf[0])), C.int(RMR_MAX_MEID_LEN))
+       len := C.rmr_bytes2meid(cMBuf, (*C.uchar)(unsafe.Pointer(&meidBuf[0])), C.int(RMR_MAX_MEID_LEN))
        if int(len) != RMR_MAX_MEID_LEN {
                ctx.Logger.Errorf(
                        "#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to copy meid data to allocated RMR message buffer")
diff --git a/RSM/rsmdb/rsm_reader.go b/RSM/rsmdb/rsm_reader.go
new file mode 100644 (file)
index 0000000..852346b
--- /dev/null
@@ -0,0 +1,85 @@
+//
+// 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 rsmdb
+
+import (
+       "encoding/json"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
+       "reflect"
+       "rsm/models"
+)
+
+type rsmReaderInstance struct {
+       sdl common.ISdlInstance
+}
+
+// RsmReader interface allows retrieving data from redis BD by various keys
+type RsmReader interface {
+       GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error)
+       GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error)
+}
+
+// GetRsmReader returns reference to RsmReader
+func GetRsmReader(sdl common.ISdlInstance) RsmReader {
+       return &rsmReaderInstance{sdl: sdl}
+}
+
+// GetRsmRanInfo returns the rsm data associated with ran 'ranName'
+func (r *rsmReaderInstance) GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error) {
+
+       key, err := common.ValidateAndBuildNodeBNameKey(ranName)
+       if err != nil {
+               return nil, err
+       }
+
+       rsmRanInfo := &models.RsmRanInfo{}
+
+       err = r.getByKeyAndUnmarshal(key, rsmRanInfo)
+
+       if err != nil {
+               return nil, err
+       }
+
+       return rsmRanInfo, nil
+}
+
+// GetRsmGeneralConfiguration returns resource status request related configuration
+func (r *rsmReaderInstance) GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) {
+       cfg := &models.RsmGeneralConfiguration{}
+       err := r.getByKeyAndUnmarshal(buildRsmGeneralConfigurationKey(), cfg)
+       return cfg, err
+}
+
+// getByKeyAndUnmarshal returns the value that is associated with key 'key' as a Go structure
+func (r *rsmReaderInstance) getByKeyAndUnmarshal(key string, entity interface{}) error {
+       data, err := r.sdl.Get([]string{key})
+       if err != nil {
+               return common.NewInternalError(err)
+       }
+       if data != nil && data[key] != nil {
+               err = json.Unmarshal([]byte(data[key].(string)), entity)
+               if err != nil {
+                       return common.NewInternalError(err)
+               }
+               return nil
+       }
+       return common.NewResourceNotFoundErrorf("#rsmReader.getByKeyAndUnmarshal - entity of type %s not found. Key: %s", reflect.TypeOf(entity).String(), key)
+}
+
+func buildRsmGeneralConfigurationKey() string {
+       return "CFG:GENERAL:v1.0.0"
+}
diff --git a/RSM/rsmdb/rsm_reader_test.go b/RSM/rsmdb/rsm_reader_test.go
new file mode 100644 (file)
index 0000000..e1703df
--- /dev/null
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ *
+ *   Copyright (c) 2019 AT&T Intellectual Property.
+ *
+ *   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 rsmdb
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
+//     "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
+       "github.com/stretchr/testify/assert"
+//     "os"
+       "rsm/enums"
+       "rsm/mocks"
+       "rsm/models"
+       "testing"
+)
+
+func TestGetRsmRanInfo(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+       ranName := "test1"
+       key, _ := common.ValidateAndBuildNodeBNameKey(ranName)
+       infoAsGoType := models.RsmRanInfo{
+               RanName:           ranName,
+               Enb1MeasurementId: 1,
+               Enb2MeasurementId: 2,
+               Action:            enums.Start,
+               ActionStatus:      false,
+       }
+       infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}"
+       sdl.On("Get", []string{key}).Return(map[string]interface{}{key: infoAsDbType}, nil)
+       info, err := reader.GetRsmRanInfo(ranName)
+       if err != nil {
+               t.Errorf("want: success, got: error: %v\n", err)
+       }
+       assert.Equal(t, info, &infoAsGoType)
+}
+
+func TestGetRsmRanInfoValidationError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+       ranName := ""
+       key, _ := common.ValidateAndBuildNodeBNameKey(ranName)
+       sdl.On("Get", []string{key}).Return(map[string]interface{}{key: ""}, nil)
+       _, err := reader.GetRsmRanInfo(ranName)
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "#utils.ValidateAndBuildNodeBNameKey - an empty inventory name received")
+}
+
+func TestGetRsmRanInfoDbError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+       ranName := "test1"
+       key, _ := common.ValidateAndBuildNodeBNameKey(ranName)
+       sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), fmt.Errorf("db error"))
+       _, err := reader.GetRsmRanInfo(ranName)
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "db error")
+}
+
+func TestGetGeneralConfiguration(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+       var testCases = []struct {
+               cfgAsGoType models.RsmGeneralConfiguration
+               cfgAsDbType string
+       }{
+               {
+                       cfgAsGoType: models.RsmGeneralConfiguration{
+                               EnableResourceStatus:         true,
+                               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,
+                       },
+
+                       cfgAsDbType: "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}",
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.cfgAsDbType, func(t *testing.T) {
+                       key := buildRsmGeneralConfigurationKey()
+                       sdl.On("Get", []string{key}).Return(map[string]interface{}{key: tc.cfgAsDbType}, nil)
+                       cfg, err := reader.GetRsmGeneralConfiguration()
+                       if err != nil {
+                               t.Errorf("want: success, got: error: %v\n", err)
+                       }
+                       assert.Equal(t, cfg, &tc.cfgAsGoType)
+               })
+       }
+}
+
+func TestGetGeneralConfigurationNotFound(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+
+       key := buildRsmGeneralConfigurationKey()
+       sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), nil)
+       _, err := reader.GetRsmGeneralConfiguration()
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "#rsmReader.getByKeyAndUnmarshal - entity of type *models.RsmGeneralConfiguration not found. Key: CFG:GENERAL:v1.0.0")
+}
+
+func TestGetGeneralConfigurationDbError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+
+       key := buildRsmGeneralConfigurationKey()
+       sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), fmt.Errorf("db error"))
+       _, err := reader.GetRsmGeneralConfiguration()
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "db error")
+}
+
+func TestGetGeneralConfigurationUnmarshalError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       reader := GetRsmReader(sdl)
+       cfgAsDbTYpe := "{\"enableResourceStatus\":true, partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}"
+       key := buildRsmGeneralConfigurationKey()
+       sdl.On("Get", []string{key}).Return(map[string]interface{}{key: cfgAsDbTYpe}, nil)
+       _, err := reader.GetRsmGeneralConfiguration()
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "invalid character 'p' looking for beginning of object key string")
+}
+
+/*
+Test against redis.
+Test execution depends on the existence of the environment variable DBAAS_SERVICE_HOST.
+*
+
+func TestGetGeneralConfigurationIntegration(t *testing.T) {
+       if len(os.Getenv("DBAAS_SERVICE_HOST")) == 0 {
+               return
+       }
+       db := sdlgo.NewDatabase()
+       sdl := sdlgo.NewSdlInstance("rsm", db)
+       reader := GetRsmReader(sdl)
+       cfgAsGoType := models.RsmGeneralConfiguration{
+               EnableResourceStatus:         true,
+               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,
+       }
+       cfg, err := reader.GetRsmGeneralConfiguration()
+       if err != nil {
+               t.Errorf("want: success, got: error: %v\n", err)
+       }
+
+       assert.Equal(t, &cfgAsGoType, cfg)
+}
+*/
\ No newline at end of file
diff --git a/RSM/rsmdb/rsm_writer.go b/RSM/rsmdb/rsm_writer.go
new file mode 100644 (file)
index 0000000..58c56c1
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// 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 rsmdb
+
+import (
+       "encoding/json"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
+       "rsm/models"
+)
+
+type rsmWriterInstance struct {
+       sdl common.ISdlInstance
+}
+
+// RsmWriter interface allows inserting/updating data to/in redis BD with various keys
+type RsmWriter interface {
+       SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error
+       SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error
+}
+
+// GetRsmWriter returns reference to RsmWriter
+func GetRsmWriter(sdl common.ISdlInstance) RsmWriter {
+       return &rsmWriterInstance{sdl: sdl}
+}
+
+// SaveRsmRanInfo saves the ran related rsm data with key RanName
+func (r *rsmWriterInstance) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error {
+
+       nodebNameKey, err := common.ValidateAndBuildNodeBNameKey(rsmRanInfo.RanName)
+
+       if err != nil {
+               return err
+       }
+
+       return r.SaveWithKeyAndMarshal(nodebNameKey, rsmRanInfo)
+}
+
+// SaveRsmGeneralConfiguration saves the resource status request related configuration
+func (r *rsmWriterInstance) SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error {
+
+       return r.SaveWithKeyAndMarshal(buildRsmGeneralConfigurationKey(), cfg)
+}
+
+
+// SaveWithKeyAndMarshal marshals the Go structure to json and saves it to the DB with key 'key'
+func (r *rsmWriterInstance) SaveWithKeyAndMarshal(key string, entity interface{}) error {
+
+       data, err := json.Marshal(entity)
+
+       if err != nil {
+               return common.NewInternalError(err)
+       }
+
+       var pairs []interface{}
+       pairs = append(pairs, key, data)
+
+       err = r.sdl.Set(pairs)
+
+       if err != nil {
+               return common.NewInternalError(err)
+       }
+
+       return nil
+}
diff --git a/RSM/rsmdb/rsm_writer_test.go b/RSM/rsmdb/rsm_writer_test.go
new file mode 100644 (file)
index 0000000..627c2f1
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ *
+ *   Copyright (c) 2019 AT&T Intellectual Property.
+ *
+ *   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 rsmdb
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
+       "github.com/stretchr/testify/assert"
+       "rsm/enums"
+       "rsm/mocks"
+       "rsm/models"
+       "testing"
+)
+
+func TestSaveRsmRanInfo(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       writer := GetRsmWriter(sdl)
+       ranName := "test1"
+       key, _ := common.ValidateAndBuildNodeBNameKey(ranName)
+       infoAsGoType := models.RsmRanInfo{
+               RanName:           ranName,
+               Enb1MeasurementId: 1,
+               Enb2MeasurementId: 2,
+               Action:            enums.Start,
+               ActionStatus:      false,
+       }
+       infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}"
+       sdl.On("Set",[]interface{}{[]interface{}{key, []byte(infoAsDbType)}}).Return(nil)
+       err := writer.SaveRsmRanInfo(&infoAsGoType)
+       if err != nil {
+               t.Errorf("want: success, got: error: %v\n", err)
+       }
+       sdl.AssertNumberOfCalls(t, "Set",1)
+}
+
+
+func TestSaveRsmRanInfoValidationError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       writer := GetRsmWriter(sdl)
+       ranName := ""
+       key, _ := common.ValidateAndBuildNodeBNameKey(ranName)
+       infoAsGoType := models.RsmRanInfo{
+               RanName:           ranName,
+               Enb1MeasurementId: 1,
+               Enb2MeasurementId: 2,
+               Action:            enums.Start,
+               ActionStatus:      false,
+       }
+       infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}"
+       sdl.On("Set",[]interface{}{[]interface{}{key, []byte(infoAsDbType)}}).Return(nil)
+       err := writer.SaveRsmRanInfo(&infoAsGoType)
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "#utils.ValidateAndBuildNodeBNameKey - an empty inventory name received")
+}
+
+
+func TestSaveGeneralConfiguration(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       writer := GetRsmWriter(sdl)
+       var testCases = []struct {
+               cfgAsGoType models.RsmGeneralConfiguration
+               cfgAsDbType string
+       }{
+               {
+                       cfgAsGoType: models.RsmGeneralConfiguration{
+                               EnableResourceStatus:         true,
+                               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,
+                       },
+
+                       cfgAsDbType: "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}",
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.cfgAsDbType, func(t *testing.T) {
+                       key:= buildRsmGeneralConfigurationKey()
+                       sdl.On("Set",[]interface{}{[]interface{}{key, []byte(tc.cfgAsDbType)}}).Return(nil)
+                       err := writer.SaveRsmGeneralConfiguration(&tc.cfgAsGoType)
+                       if err != nil {
+                               t.Errorf("want: success, got: error: %v\n", err)
+                       }
+
+                       sdl.AssertNumberOfCalls(t, "Set",1)
+               })
+       }
+}
+
+
+func TestSaveGeneralConfigurationDbError(t *testing.T) {
+       sdl := &mocks.MockSdlInstance{}
+       writer := GetRsmWriter(sdl)
+
+       cfgAsGoType:= models.RsmGeneralConfiguration{
+               EnableResourceStatus:         true,
+               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,
+       }
+       cfgAsDbTYpe:= "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}"
+       key:= buildRsmGeneralConfigurationKey()
+       sdl.On("Set",[]interface{}{[]interface{}{key, []byte(cfgAsDbTYpe)}}).Return(fmt.Errorf("db error"))
+       err := writer.SaveRsmGeneralConfiguration(&cfgAsGoType)
+       assert.NotNil(t, err)
+       assert.Equal(t, err.Error(), "db error")
+}
index 7650c46..18f40e7 100644 (file)
@@ -21,6 +21,6 @@
 package rsmerrors
 
 type BaseError struct {
-       Code int
+       Code    int
        Message string
 }
index 20fc8e3..75e61f9 100644 (file)
@@ -25,9 +25,9 @@ type HeaderValidationError struct {
 }
 
 func NewHeaderValidationError() *HeaderValidationError {
-       return &HeaderValidationError {
+       return &HeaderValidationError{
                &BaseError{
-                       Code: 415,
+                       Code:    415,
                        Message: "Header validation error",
                },
        }
index 3e8ea87..c31e5d5 100644 (file)
@@ -25,9 +25,9 @@ type InternalError struct {
 }
 
 func NewInternalError() *InternalError {
-       return &InternalError {
+       return &InternalError{
                &BaseError{
-                       Code: 501,
+                       Code:    501,
                        Message: "Internal Server Error. Please try again later",
                },
        }
index 1d5bce9..36fb202 100644 (file)
@@ -20,7 +20,6 @@
 
 package rsmerrors
 
-
 type InvalidJsonError struct {
        *BaseError
 }
@@ -37,4 +36,3 @@ func NewInvalidJsonError() *InvalidJsonError {
 func (e *InvalidJsonError) Error() string {
        return e.Message
 }
-
index a6babd5..189094d 100644 (file)
@@ -25,9 +25,9 @@ type RnibDbError struct {
 }
 
 func NewRnibDbError() *RnibDbError {
-       return &RnibDbError {
+       return &RnibDbError{
                &BaseError{
-                       Code: 500,
+                       Code:    500,
                        Message: "RNIB error",
                },
        }
@@ -35,4 +35,4 @@ func NewRnibDbError() *RnibDbError {
 
 func (e *RnibDbError) Error() string {
        return e.Message
-}
\ No newline at end of file
+}
diff --git a/RSM/rsmerrors/rsm_error.go b/RSM/rsmerrors/rsm_error.go
new file mode 100644 (file)
index 0000000..e4ca044
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// 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 rsmerrors
+
+import "fmt"
+
+type RsmError struct {
+       *BaseError
+}
+
+func NewRsmError(numberOfFails int) *RsmError {
+       return &RsmError{
+               &BaseError{
+                       Code:    503,
+                       Message: fmt.Sprintf("Did not send %d resource status requests to RMR.", numberOfFails),
+               },
+       }
+}
+
+func (e *RsmError) Error() string {
+       return e.Message
+}
index 1fc0b74..6f38b07 100644 (file)
@@ -30,7 +30,7 @@ func NewWrongStateError(activityName string, state string) *WrongStateError {
        return &WrongStateError{
                &BaseError{
                        Code:    403,
-                       Message: fmt.Sprintf("Activity %s rejected. RAN current state %s does not allow its execution ", activityName, state) ,
+                       Message: fmt.Sprintf("Activity %s rejected. RAN current state %s does not allow its execution ", activityName, state),
                },
        }
 }
diff --git a/RSM/services/resource_status_service.go b/RSM/services/resource_status_service.go
new file mode 100644 (file)
index 0000000..6f0df7e
--- /dev/null
@@ -0,0 +1,121 @@
+//
+// 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 services
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
+       "rsm/e2pdus"
+       "rsm/enums"
+       "rsm/logger"
+       "rsm/models"
+       "rsm/rmrcgo"
+       "rsm/services/rmrsender"
+)
+
+type ResourceStatusService struct {
+       logger    *logger.Logger
+       rmrSender *rmrsender.RmrSender
+}
+
+type IResourceStatusService interface {
+       BuildAndSendInitiateRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64) error
+       BuildAndSendStopRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64, enb2MeasurementId int64) error
+}
+
+func NewResourceStatusService(logger *logger.Logger, rmrSender *rmrsender.RmrSender) *ResourceStatusService {
+       return &ResourceStatusService{
+               logger:    logger,
+               rmrSender: rmrSender,
+       }
+}
+
+func (m *ResourceStatusService) BuildAndSendInitiateRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64) error {
+
+       return m.buildAndSendResourceStatusRequest(enums.Registration_Request_start, nodeb, config, enb1MeasurementId, 0)
+}
+
+func (m *ResourceStatusService) BuildAndSendStopRequest(nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64, enb2MeasurementId int64) error {
+
+       return m.buildAndSendResourceStatusRequest(enums.Registration_Request_stop, nodeb, config, enb1MeasurementId, enb2MeasurementId)
+}
+
+func (m *ResourceStatusService) buildAndSendResourceStatusRequest(registrationRequest enums.Registration_Request, nodeb *entities.NodebInfo, config *models.RsmGeneralConfiguration, enb1MeasurementId int64, enb2MeasurementId int64) error {
+
+       cellIdList, err := m.extractCellIdList(nodeb)
+
+       if err != nil {
+               return err
+       }
+
+       requestParams := buildResourceStatusRequestParams(config, cellIdList, enb1MeasurementId, enb2MeasurementId)
+
+       payload, payloadAsString, err := e2pdus.BuildPackedResourceStatusRequest(registrationRequest, requestParams, e2pdus.MaxAsn1PackedBufferSize, e2pdus.MaxAsn1CodecMessageBufferSize, m.logger.DebugEnabled())
+
+       if err != nil {
+               m.logger.Errorf("#ResourceStatusService.buildAndSendResourceStatusRequest - RAN name: %s. Failed to build and pack resource status %s request. error: %s", nodeb.RanName, registrationRequest, err)
+               return err
+       }
+
+       m.logger.Debugf("#ResourceStatusService.buildAndSendResourceStatusRequest - RAN name: %s. Successfully build packed payload: %s", nodeb.RanName, payloadAsString)
+       rmrMsg := models.NewRmrMessage(rmrcgo.RicResStatusReq, nodeb.RanName, payload)
+
+       return m.rmrSender.Send(rmrMsg)
+}
+
+func (m *ResourceStatusService) extractCellIdList(nodeb *entities.NodebInfo) ([]string, error) {
+
+       enb, ok := nodeb.Configuration.(*entities.NodebInfo_Enb)
+
+       if !ok {
+               m.logger.Errorf("#ResourceStatusService.extractCellIdList - RAN name: %s - invalid configuration", nodeb.RanName)
+               return []string{}, fmt.Errorf("invalid configuration for RAN %s", nodeb.RanName)
+       }
+
+       cells := enb.Enb.ServedCells
+
+       if len(cells) == 0 {
+               m.logger.Errorf("#ResourceStatusService.extractCellIdList - RAN name: %s - empty cell list", nodeb.RanName)
+               return []string{}, fmt.Errorf("empty cell list for RAN %s", nodeb.RanName)
+       }
+
+       cellIdList := make([]string, len(cells))
+       for index, cellInfo := range cells {
+               cellIdList[index] = cellInfo.CellId
+       }
+
+       return cellIdList, nil
+}
+
+func buildResourceStatusRequestParams(config *models.RsmGeneralConfiguration, cellIdList []string, enb1MeasurementId int64, enb2MeasurementId int64) *e2pdus.ResourceStatusRequestData {
+       return &e2pdus.ResourceStatusRequestData{
+               CellIdList:                   cellIdList,
+               MeasurementID:                e2pdus.Measurement_ID(enb1MeasurementId),
+               MeasurementID2:               e2pdus.Measurement_ID(enb2MeasurementId),
+               PartialSuccessAllowed:        config.PartialSuccessAllowed,
+               PrbPeriodic:                  config.PrbPeriodic,
+               TnlLoadIndPeriodic:           config.TnlLoadIndPeriodic,
+               HwLoadIndPeriodic:            config.HwLoadIndPeriodic,
+               AbsStatusPeriodic:            config.AbsStatusPeriodic,
+               RsrpMeasurementPeriodic:      config.RsrpMeasurementPeriodic,
+               CsiPeriodic:                  config.CsiPeriodic,
+               PeriodicityMS:                config.PeriodicityMs,
+               PeriodicityRsrpMeasurementMS: config.PeriodicityRsrpMeasurementMs,
+               PeriodicityCsiMS:             config.PeriodicityCsiMs,
+       }
+}
diff --git a/RSM/services/resource_status_service_test.go b/RSM/services/resource_status_service_test.go
new file mode 100644 (file)
index 0000000..9b4e962
--- /dev/null
@@ -0,0 +1,246 @@
+//
+// 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 services
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
+       "github.com/stretchr/testify/assert"
+       "rsm/enums"
+       "rsm/logger"
+       "rsm/mocks"
+       "rsm/models"
+       "rsm/rmrcgo"
+       "rsm/rsmerrors"
+       "rsm/services/rmrsender"
+       "rsm/tests"
+       "testing"
+)
+
+const RanName = "test"
+const NodebOneCellPackedExample = "0009003c00000800270003000000001c00010000260004fe000000001d400d00001f40080002f8290007ab00001e4001000040400100006d4001400091400120"
+const NodebTwoCellsPackedExample = "0009004800000800270003000000001c00010000260004fe000000001d401901001f40080002f8290007ab00001f40080002f8290007ab50001e4001000040400100006d4001400091400120"
+const StopPackedExample = "0009004f0000090027000300000000280003000001001c00014000260004fe000000001d401901001f40080002f8290007ab00001f40080002f8290007ab50001e4001000040400100006d4001400091400120"
+
+func initResourceStatusServiceTest(t *testing.T) (*mocks.RmrMessengerMock, *models.RsmGeneralConfiguration, *ResourceStatusService) {
+       logger, err := logger.InitLogger(logger.DebugLevel)
+       if err != nil {
+               t.Errorf("#... - failed to initialize logger, error: %s", err)
+       }
+
+       rmrMessengerMock := &mocks.RmrMessengerMock{}
+       rmrSender := InitRmrSender(rmrMessengerMock, logger)
+       resourceStatusService := NewResourceStatusService(logger, rmrSender)
+
+       rsmGeneralConfiguration := models.RsmGeneralConfiguration{
+               EnableResourceStatus:         true,
+               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,
+       }
+
+       return rmrMessengerMock, &rsmGeneralConfiguration, resourceStatusService
+}
+
+func TestOneCellSuccess(t *testing.T) {
+       cellId := "02f829:0007ab00"
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+
+       xaction := []byte(RanName)
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId}},
+                       },
+               },
+       }
+
+       var expectedPayload []byte
+       _, _ = fmt.Sscanf(NodebOneCellPackedExample, "%x", &expectedPayload)
+       var err error
+       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
+       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, err)
+       err = resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId)
+       assert.Nil(t, err)
+       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
+}
+
+func TestTwoCellsSuccess(t *testing.T) {
+       cellId1 := "02f829:0007ab00"
+       cellId2 := "02f829:0007ab50"
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+       xaction := []byte(RanName)
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}},
+                       },
+               },
+       }
+
+       var expectedPayload []byte
+       _, _ = fmt.Sscanf(NodebTwoCellsPackedExample, "%x", &expectedPayload)
+       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
+       var err error
+       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, err)
+       err = resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId)
+       assert.Nil(t, err)
+       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
+}
+
+func TestOneCellSendFailure(t *testing.T) {
+       cellId := "02f829:0007ab00"
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+
+       xaction := []byte(RanName)
+       var err error
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId}},
+                       },
+               },
+       }
+
+       var expectedPayload []byte
+       _, _ = fmt.Sscanf(NodebOneCellPackedExample, "%x", &expectedPayload)
+       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
+       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, rsmerrors.NewRmrError())
+       err = resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, 1)
+       assert.NotNil(t, err)
+       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
+}
+
+
+
+func TestNodebConfigurationFailure(t *testing.T) {
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+       }
+
+       err := resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId)
+       assert.NotNil(t, err)
+       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
+}
+
+func TestNodebEmptyCellList(t *testing.T) {
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{},
+                       },
+               },
+       }
+
+       err := resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId)
+       assert.NotNil(t, err)
+       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
+}
+
+func TestPackFailure(t *testing.T) {
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: ""}},
+                       },
+               },
+       }
+
+       err := resourceStatusService.BuildAndSendInitiateRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId)
+       assert.NotNil(t, err)
+       rmrMessengerMock.AssertNotCalled(t, "SendMsg")
+}
+
+func TestBuildAndSendStopRequestSuccess(t *testing.T) {
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+
+       cellId1 := "02f829:0007ab00"
+       cellId2 := "02f829:0007ab50"
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}},
+                       },
+               },
+       }
+       xaction := []byte(RanName)
+       var expectedPayload []byte
+       _, _ = fmt.Sscanf(StopPackedExample, "%x", &expectedPayload)
+       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
+       var err error
+       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, err)
+       err = resourceStatusService.BuildAndSendStopRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId, 2)
+       assert.Nil(t, err)
+       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
+}
+
+func TestBuildAndSendStopRequestSendFailure(t *testing.T) {
+       rmrMessengerMock, rsmGeneralConfiguration, resourceStatusService := initResourceStatusServiceTest(t)
+
+       xaction := []byte(RanName)
+       cellId1 := "02f829:0007ab00"
+       cellId2 := "02f829:0007ab50"
+       nodebInfo := &entities.NodebInfo{
+               RanName:          RanName,
+               ConnectionStatus: entities.ConnectionStatus_CONNECTED,
+               Configuration: &entities.NodebInfo_Enb{
+                       Enb: &entities.Enb{
+                               ServedCells: []*entities.ServedCellInfo{{CellId: cellId1}, {CellId: cellId2}},
+                       },
+               },
+       }
+
+       var err error
+       var expectedPayload []byte
+       _, _ = fmt.Sscanf(StopPackedExample, "%x", &expectedPayload)
+       expectedMbuf := rmrcgo.NewMBuf(rmrcgo.RicResStatusReq, len(expectedPayload), RanName, &expectedPayload, &xaction)
+       rmrMessengerMock.On("SendMsg", expectedMbuf).Return(&rmrcgo.MBuf{}, rsmerrors.NewRmrError())
+       err = resourceStatusService.BuildAndSendStopRequest(nodebInfo, rsmGeneralConfiguration, enums.Enb1MeasurementId, 2)
+
+       assert.NotNil(t, err)
+       rmrMessengerMock.AssertCalled(t, "SendMsg", expectedMbuf)
+}
+
+func InitRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender {
+       rmrMessenger := rmrcgo.RmrMessenger(rmrMessengerMock)
+       rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger)
+       return rmrsender.NewRmrSender(log, rmrMessenger)
+}
index b678e05..18ece2f 100644 (file)
@@ -54,4 +54,4 @@ func (r *RmrReceiver) ListenAndHandle() {
                // TODO: go routine?
                r.nManager.HandleMessage(mbuf)
        }
-}
\ No newline at end of file
+}
index f62160e..7bcbbf9 100644 (file)
@@ -23,11 +23,13 @@ package rmrreceiver
 import (
        "fmt"
        "rsm/configuration"
+       "rsm/converters"
+       "rsm/e2pdus"
        "rsm/logger"
-       "rsm/managers"
        "rsm/managers/rmrmanagers"
        "rsm/mocks"
        "rsm/rmrcgo"
+       "rsm/services"
        "rsm/tests"
        "rsm/tests/testhelper"
        "testing"
@@ -58,10 +60,11 @@ func initRmrReceiver(t *testing.T) *RmrReceiver {
        if err != nil {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
-       resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
+       resourceStatusService := services.NewResourceStatusService(logger, rmrSender)
 
        rmrMessenger := initRmrMessenger(logger)
-       manager := rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+       unpacker := converters.NewX2apPduUnpacker(logger, e2pdus.MaxAsn1CodecMessageBufferSize)
+       manager := rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusService, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        return NewRmrReceiver(logger, rmrMessenger, manager)
 }
index 43bb784..e422070 100644 (file)
@@ -51,4 +51,4 @@ func (r *RmrSender) Send(rmrMessage *models.RmrMessage) error {
 
        r.logger.Infof("#RmrSender.Send - RAN name: %s , Message type: %d - Successfully sent RMR message", rmrMessage.RanName, rmrMessage.MsgType)
        return nil
-}
\ No newline at end of file
+}
index 4241d50..2d5325e 100644 (file)
@@ -77,4 +77,4 @@ func InitLog(t *testing.T) *logger.Logger {
                t.Errorf("#tests.initLog - failed to initialize logger, error: %s", err)
        }
        return log
-}
\ No newline at end of file
+}
index 1133af4..58b604c 100644 (file)
@@ -27,51 +27,127 @@ import (
        "net"
        "rsm/configuration"
        "rsm/logger"
+       "rsm/models"
+       "rsm/rsmdb"
        "time"
 )
 
 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
 }
 
 type rNibDataService struct {
-       logger             *logger.Logger
-       rnibReaderProvider func() reader.RNibReader
-       maxAttempts        int
-       retryInterval      time.Duration
+       logger        *logger.Logger
+       rnibReader    reader.RNibReader
+       rsmReader     rsmdb.RsmReader
+       rsmWriter     rsmdb.RsmWriter
+       maxAttempts   int
+       retryInterval time.Duration
 }
 
-func NewRnibDataService(logger *logger.Logger, config *configuration.Configuration, rnibReaderProvider func() reader.RNibReader) *rNibDataService {
+func NewRnibDataService(logger *logger.Logger, config *configuration.Configuration, rnibReader reader.RNibReader, rsmReader rsmdb.RsmReader, rsmWriter rsmdb.RsmWriter) *rNibDataService {
        return &rNibDataService{
-               logger:             logger,
-               rnibReaderProvider: rnibReaderProvider,
-               maxAttempts:        config.Rnib.MaxRnibConnectionAttempts,
-               retryInterval:      time.Duration(config.Rnib.RnibRetryIntervalMs) * time.Millisecond,
+               logger:        logger,
+               rnibReader:    rnibReader,
+               rsmReader:     rsmReader,
+               rsmWriter:     rsmWriter,
+               maxAttempts:   config.Rnib.MaxRnibConnectionAttempts,
+               retryInterval: time.Duration(config.Rnib.RnibRetryIntervalMs) * time.Millisecond,
        }
 }
 
-func (w *rNibDataService) GetNodeb(ranName string) (*entities.NodebInfo, error) {
-       w.logger.Infof("#RnibDataService.GetNodeb - ranName: %s", ranName)
+func (w *rNibDataService) GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) {
+       var rsmGeneralConfiguration *models.RsmGeneralConfiguration = nil
+
+       err := w.retry("GetRsmGeneralConfiguration", func() (err error) {
+               rsmGeneralConfiguration, err = w.rsmReader.GetRsmGeneralConfiguration()
+               return
+       })
+
+       if err == nil {
+               w.logger.Infof("#RnibDataService.GetRsmGeneralConfiguration - configuration: %+v", *rsmGeneralConfiguration)
+       }
+
+       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
+
+       err := w.retry("GetRsmRanInfo", func() (err error) {
+               rsmRanInfo, err = w.rsmReader.GetRsmRanInfo(ranName)
+               return
+       })
+
+       if err == nil {
+               w.logger.Infof("#RnibDataService.GetRsmRanInfo - RAN name: %s, RsmRanInfo: %+v", ranName, *rsmRanInfo)
+       }
 
+       return rsmRanInfo, err
+}
+
+func (w *rNibDataService) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error {
+       err := w.retry("SaveRsmRanInfo", func() (err error) {
+               err = w.rsmWriter.SaveRsmRanInfo(rsmRanInfo)
+               return
+       })
+
+       if err == nil {
+               w.logger.Infof("#RnibDataService.SaveRsmRanInfo - RAN name: %s, RsmRanInfo: %+v", rsmRanInfo.RanName, *rsmRanInfo)
+       }
+
+       return err
+}
+
+func (w *rNibDataService) GetNodeb(ranName string) (*entities.NodebInfo, error) {
        var nodeb *entities.NodebInfo = nil
 
        err := w.retry("GetNodeb", func() (err error) {
-               nodeb, err = w.rnibReaderProvider().GetNodeb(ranName)
+               nodeb, err = w.rnibReader.GetNodeb(ranName)
                return
        })
 
        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")
 
        var nodeIds []*entities.NbIdentity = nil
 
        err := w.retry("GetListNodebIds", func() (err error) {
-               nodeIds, err = w.rnibReaderProvider().GetListNodebIds()
+               nodeIds, err = w.rnibReader.GetListNodebIds()
                return
        })
 
@@ -80,7 +156,7 @@ func (w *rNibDataService) GetListNodebIds() ([]*entities.NbIdentity, error) {
 
 func (w *rNibDataService) PingRnib() bool {
        err := w.retry("GetListNodebIds", func() (err error) {
-               _, err = w.rnibReaderProvider().GetListNodebIds()
+               _, err = w.rnibReader.GetListNodebIds()
                return
        })
 
@@ -96,6 +172,7 @@ func (w *rNibDataService) retry(rnibFunc string, f func() error) (err error) {
                        return
                }
                if !isRnibConnectionError(err) {
+                       w.logger.Errorf("#RnibDataService - error in %s: %s", rnibFunc, err)
                        return err
                }
                if i >= attempts {
index 2582c4f..ab0e474 100644 (file)
@@ -24,7 +24,6 @@ import (
        "fmt"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
        "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
-       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
        "github.com/stretchr/testify/assert"
        "net"
        "rsm/configuration"
@@ -50,15 +49,14 @@ func setupRnibDataServiceTestWithMaxAttempts(t *testing.T, maxAttempts int) (*rN
        }
        config.Rnib.MaxRnibConnectionAttempts = maxAttempts
 
-       readerMock := &mocks.RnibReaderMock{}
-       rnibReaderProvider := func() reader.RNibReader {
-               return readerMock
-       }
+       rnibReaderMock := &mocks.RnibReaderMock{}
+       rsmReaderMock := &mocks.RsmReaderMock{}
+       rsmWriterMock := &mocks.RsmWriterMock{}
 
-       rnibDataService := NewRnibDataService(logger, config, rnibReaderProvider)
+       rnibDataService := NewRnibDataService(logger, config, rnibReaderMock, rsmReaderMock, rsmWriterMock)
        assert.NotNil(t, rnibDataService)
 
-       return rnibDataService, readerMock
+       return rnibDataService, rnibReaderMock
 }
 
 func TestSuccessfulGetNodeb(t *testing.T) {
@@ -84,7 +82,7 @@ func TestConnFailureGetNodeb(t *testing.T) {
 
        res, err := rnibDataService.GetNodeb(invName)
        readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
-       assert.True(t, strings.Contains(err.Error(), "connection error"))
+       assert.True(t, strings.Contains(err.Error(), "connection error"))
        assert.Equal(t, nodeb, res)
 }
 
@@ -109,7 +107,7 @@ func TestConnFailureGetNodebIdList(t *testing.T) {
 
        res, err := rnibDataService.GetListNodebIds()
        readerMock.AssertNumberOfCalls(t, "GetListNodebIds", 3)
-       assert.True(t, strings.Contains(err.Error(), "connection error"))
+       assert.True(t, strings.Contains(err.Error(), "connection error"))
        assert.Equal(t, nodeIds, res)
 }
 
@@ -125,12 +123,12 @@ func TestConnFailureTwiceGetNodebIdList(t *testing.T) {
 
        res, err := rnibDataService.GetListNodebIds()
        readerMock.AssertNumberOfCalls(t, "GetListNodebIds", 3)
-       assert.True(t, strings.Contains(err.Error(), "connection error"))
+       assert.True(t, strings.Contains(err.Error(), "connection error"))
        assert.Equal(t, nodeIds, res)
 
        res2, err := rnibDataService.GetNodeb(invName)
        readerMock.AssertNumberOfCalls(t, "GetNodeb", 3)
-       assert.True(t, strings.Contains(err.Error(), "connection error"))
+       assert.True(t, strings.Contains(err.Error(), "connection error"))
        assert.Equal(t, nodeb, res2)
 }
 
@@ -143,7 +141,7 @@ func TestConnFailureWithAnotherConfig(t *testing.T) {
 
        res, err := rnibDataService.GetListNodebIds()
        readerMock.AssertNumberOfCalls(t, "GetListNodebIds", 5)
-       assert.True(t, strings.Contains(err.Error(), "connection error"))
+       assert.True(t, strings.Contains(err.Error(), "connection error"))
        assert.Equal(t, nodeIds, res)
 }
 
@@ -180,4 +178,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 f945a42..e21fa98 100644 (file)
@@ -24,6 +24,8 @@ import (
        "bytes"
        "encoding/json"
        "net/http"
+       "rsm/enums"
+       "rsm/models"
        "strconv"
 )
 
@@ -55,3 +57,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 36756a1..0000000
+++ /dev/null
@@ -1,83 +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.
-
-//  This source code is part of the near-RT RIC (RAN Intelligent Controller)
-//  platform project (RICP).
-
-
-package tests
-
-// #cgo CFLAGS: -I../3rdparty/asn1codec/inc/ -I../3rdparty/asn1codec/e2ap_engine/
-// #cgo LDFLAGS: -L ../3rdparty/asn1codec/lib/ -L../3rdparty/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 657429a..b1eba9d 100644 (file)
@@ -21,7 +21,6 @@
 package testhelper
 
 import (
-       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
        "rsm/configuration"
        "rsm/logger"
        "rsm/mocks"
@@ -53,12 +52,12 @@ func InitTestCase(t *testing.T) (services.RNibDataService, *rmrsender.RmrSender,
                t.Errorf("#tests.InitTestCase - failed to parse configuration, error: %s", err)
        }
 
-       readerMock := &mocks.RnibReaderMock{}
-       rnibReaderProvider := func() reader.RNibReader {
-               return readerMock
-       }
+       rnibReaderMock := &mocks.RnibReaderMock{}
+
+       rsmReaderMock := &mocks.RsmReaderMock{}
+       rsmWriterMock := &mocks.RsmWriterMock{}
 
        rmrSender := InitRmrSender(&mocks.RmrMessengerMock{}, logger)
-       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider)
+       rnibDataService := services.NewRnibDataService(logger, config, rnibReaderMock, rsmReaderMock, rsmWriterMock)
        return rnibDataService, rmrSender, logger
 }