[RICPLT-2595] - RSM: Parse Resource Status Successful Response & Failure. 69/1469/1
authorrh362j <ronen.hasid@intl.att.com>
Mon, 11 Nov 2019 14:35:08 +0000 (16:35 +0200)
committerrh362j <ronen.hasid@intl.att.com>
Mon, 11 Nov 2019 14:36:56 +0000 (16:36 +0200)
Signed-off-by: rh362j <ronen.hasid@intl.att.com>
Change-Id: I7b72ff614d2b609682f9b5676e6d1abef21cac21

19 files changed:
RSM/app/main.go
RSM/asn1codec/inc/resource_status_response_wrapper.h [new file with mode: 0644]
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/handlers/rmrmsghandlers/resource_status_failure_handler.go
RSM/handlers/rmrmsghandlers/resource_status_failure_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/managers/rmrmanagers/rmr_message_manager.go
RSM/managers/rmrmanagers/rmr_message_manager_test.go
RSM/mocks/resource_status_failure_converter_mock.go [moved from RSM/mocks/unpacker_mock.go with 61% similarity]
RSM/mocks/resource_status_response_converter_mock.go [new file with mode: 0644]
RSM/models/resource_status_response.go [new file with mode: 0644]
RSM/providers/rmrmsghandlerprovider/message_handler_provider.go
RSM/providers/rmrmsghandlerprovider/message_handler_provider_test.go
RSM/services/rmrreceiver/rmr_receiver_test.go

index 09a7356..5f79f9e 100644 (file)
@@ -36,8 +36,6 @@ import (
        "strconv"
 )
 
-const MaxRnibPoolInstances = 4
-
 func main() {
        config, err := configuration.ParseConfiguration()
        if err != nil {
@@ -60,7 +58,8 @@ func main() {
        rmrSender := rmrsender.NewRmrSender(logger, rmrMessenger)
 
        resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-       var rmrManager = rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,converters.NewX2apPduUnpacker(logger))
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       var rmrManager = rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        rmrReceiver := rmrreceiver.NewRmrReceiver(logger, rmrMessenger, rmrManager)
        defer rmrMessenger.Close()
diff --git a/RSM/asn1codec/inc/resource_status_response_wrapper.h b/RSM/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 */
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..c390615
--- /dev/null
@@ -0,0 +1,123 @@
+//
+// 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)}
+                       convertMeasurementFailureCauses(&item.measurementFailureCause_List, &measurementInitiationResult)
+                       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(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*models.ResourceStatusResponse, error) {
+       pdu, err := r.UnpackX2apPdu(packedBufferSize, packedBuf, maxMessageBufferSize)
+       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..3f0a36d
--- /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)
+       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(len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
+                       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)
+       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(len(payload), 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)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusFailureConverterPduOfSuccess(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger)
+       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(len(payload), 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)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusFailureConverterWrongPdu(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger)
+       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(len(payload), 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)
+               }
+       } 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..9d0b874
--- /dev/null
@@ -0,0 +1,168 @@
+//
+// 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(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*models.ResourceStatusResponse, error)
+       UnpackX2apPduAsString(packedBufferSize int, 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 {
+                               convertMeasurementFailureCauses(item.measurementFailureCause_List, &measurementInitiationResult)
+                       }
+                       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(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*models.ResourceStatusResponse, error) {
+       pdu, err := r.UnpackX2apPdu(packedBufferSize, packedBuf, maxMessageBufferSize)
+       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..5671fe7
--- /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)
+       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(len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/)
+                       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)
+       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(len(payload), 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)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusResponseConverterPduOfFailure(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger)
+       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(len(payload), 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)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
+
+func TestResourceStatusResponseConverterWrongPdu(t *testing.T) {
+       logger, _ := logger.InitLogger(logger.InfoLevel)
+       unpacker := NewX2apPduUnpacker(logger)
+       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(len(payload), 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)
+               }
+       } else {
+               t.Errorf("want failure: %s, got: success", wantError)
+
+       }
+}
index 0d49939..ac77fb0 100644 (file)
@@ -28,17 +28,13 @@ import (
        "unsafe"
 )
 
-type Asn1PduUnpacker interface {
-       UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error)
-}
-
 type X2apPduUnpacker struct {
        logger *logger.Logger
 
 }
 
-func NewX2apPduUnpacker(logger *logger.Logger) Asn1PduUnpacker {
-       return &X2apPduUnpacker{logger :logger}
+func NewX2apPduUnpacker(logger *logger.Logger) X2apPduUnpacker {
+       return X2apPduUnpacker{logger :logger}
 }
 
 func (r X2apPduUnpacker) UnpackX2apPdu(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*C.E2AP_PDU_t, error) {
index 7ae1167..32ed655 100644 (file)
@@ -25,25 +25,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 {
+       if h.logger.DebugEnabled() {
+               pduAsString, err := h.converter.UnpackX2apPduAsString(request.Len, 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.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - message: %s", request.RanName, pduAsString)
        }
-}
+       response, err := h.converter.Convert(request.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
+       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 9cacf90..aff5408 100644 (file)
@@ -19,6 +19,7 @@ package rmrmsghandlers
 
 import (
        "fmt"
+       "rsm/converters"
        "rsm/e2pdus"
        "rsm/logger"
        "rsm/mocks"
@@ -27,39 +28,73 @@ import (
        "time"
 )
 
-// Verify UnpackX2apPduAsString is called
-func TestFailureHandler(t *testing.T) {
+// Verify UnpackX2apPduAsString() and Convert() are called
+func TestResourceStatusFailureHandlerConvertFailure(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{}
-       unpackerMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
-       h:= NewResourceStatusFailureHandler(logger, &unpackerMock)
+       converterMock:= mocks.ResourceStatusFailureConverterMock{}
+       converterMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).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{}
+       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.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(payloadAsString, err)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).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", 0)
+}
+
+func TestResourceStatusFailureHandler(t *testing.T) {
+       logger, err := logger.InitLogger(logger.DebugLevel)
+       if err != nil {
+               t.Errorf("#... - failed to initialize logger, error: %s", err)
+       }
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       converer:= 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, converer)
+
+       h.Handle(&req)
+}
+
+func TestResourceStatusFailureHandlerMinimalPdu(t *testing.T) {
+       logger, err := logger.InitLogger(logger.DebugLevel)
+       if err != nil {
+               t.Errorf("#... - failed to initialize logger, error: %s", err)
+       }
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       converer:= 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, converer)
+
+       h.Handle(&req)
 }
index da35d8c..7b7cb01 100644 (file)
 
 package rmrmsghandlers
 
-
 import (
-//     "rsm/converters"
-//     "rsm/e2pdus"
+       "rsm/converters"
+       "rsm/e2pdus"
        "rsm/logger"
        "rsm/models"
 )
 
 type ResourceStatusResponseHandler struct {
        logger *logger.Logger
+       converter converters.IResourceStatusResponseConverter
 }
 
-func NewResourceStatusResponseHandler(logger *logger.Logger) ResourceStatusResponseHandler {
+func NewResourceStatusResponseHandler(logger *logger.Logger, converter converters.IResourceStatusResponseConverter) ResourceStatusResponseHandler {
        return ResourceStatusResponseHandler{
-               logger:logger,
+               logger: logger,
+               converter: converter,
        }
 }
 
 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.Len, 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.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize)
+       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 for ENB1_Measurement_ID = %d", request.RanName, response.ENB1_Measurement_ID)
+               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)
 }
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..138b400
--- /dev/null
@@ -0,0 +1,108 @@
+//
+// 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"
+       "rsm/e2pdus"
+       "rsm/logger"
+       "rsm/mocks"
+       "rsm/models"
+       "testing"
+       "time"
+)
+
+// Verify UnpackX2apPduAsString() and Convert() are called
+func TestResourceStatusResponseHandler(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)}
+       converterMock:= mocks.ResourceStatusResponseConverterMock{}
+       converterMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+       h:= NewResourceStatusResponseHandler(logger, &converterMock)
+
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+}
+
+
+func TestResourceStatusResponseHandlerError(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)}
+       converterMock:= mocks.ResourceStatusResponseConverterMock{}
+
+       err = fmt.Errorf("error")
+       var payloadAsString string
+       converterMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(payloadAsString, err)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return((*models.ResourceStatusResponse)(nil), fmt.Errorf("error"))
+       h:= NewResourceStatusResponseHandler(logger, &converterMock)
+
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 0)
+}
+
+
+func TestResourceStatusResponseHandlerEnb2Mid0(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)}
+       response := &models.ResourceStatusResponse{}
+       converterMock:= mocks.ResourceStatusResponseConverterMock{}
+       converterMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(response, nil)
+       h:= NewResourceStatusResponseHandler(logger, &converterMock)
+
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+}
+
+func TestResourceStatusResponseHandlerWithMid(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)}
+       response := &models.ResourceStatusResponse{ENB1_Measurement_ID:1, ENB2_Measurement_ID:2}
+       converterMock:= mocks.ResourceStatusResponseConverterMock{}
+       converterMock.On("UnpackX2apPduAsString", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(string(payload), nil)
+       converterMock.On("Convert", req.Len, req.Payload, e2pdus.MaxAsn1CodecMessageBufferSize).Return(response, nil)
+       h:= NewResourceStatusResponseHandler(logger, &converterMock)
+
+       h.Handle(&req)
+
+       converterMock.AssertNumberOfCalls(t, "UnpackX2apPduAsString", 1)
+       converterMock.AssertNumberOfCalls(t, "Convert", 1)
+}
index a8ddce3..e1eaf1b 100644 (file)
@@ -35,8 +35,8 @@ 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, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, rsConverter converters.ResourceStatusResponseConverter, rsFailureConverter converters.ResourceStatusFailureConverter) *RmrMessageManager {
+       handlerProvider := rmrmsghandlerprovider.NewMessageHandlerProvider(logger,config, rnibDataService, rmrSender, resourceStatusInitiateManager, rsConverter, rsFailureConverter)
 
        return &RmrMessageManager{
                handlerProvider: handlerProvider,
index 23c6379..80e590d 100644 (file)
@@ -18,6 +18,7 @@ package rmrmanagers
 
 import (
        "rsm/configuration"
+       "rsm/converters"
        "rsm/managers"
        "rsm/rmrcgo"
        "rsm/tests/testhelper"
@@ -29,8 +30,8 @@ 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)
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        xactionByteArr := []byte("1111111")
        payloadByteArr := []byte("payload")
@@ -44,8 +45,8 @@ 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)
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       manager := NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        xactionByteArr := []byte("1111111")
        payloadByteArr := []byte("payload")
similarity index 61%
rename from RSM/mocks/unpacker_mock.go
rename to RSM/mocks/resource_status_failure_converter_mock.go
index 0896731..54b056c 100644 (file)
@@ -19,15 +19,21 @@ package mocks
 
 import (
        "github.com/stretchr/testify/mock"
+       "rsm/models"
 )
 
-type Asn1PduUnpackerMock struct {
+type ResourceStatusFailureConverterMock struct {
        mock.Mock
 }
 
-func (m *Asn1PduUnpackerMock)UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error){
+
+func (m *ResourceStatusFailureConverterMock)Convert(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*models.ResourceStatusResponse, error){
        args := m.Called(packedBufferSize, packedBuf, maxMessageBufferSize)
-       return args.Get(0).(string), args.Error(1)
+       return args.Get(0).(*models.ResourceStatusResponse), args.Error(1)
 }
 
+func (m *ResourceStatusFailureConverterMock)UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error){
+       args := m.Called(packedBufferSize, packedBuf, maxMessageBufferSize)
+       return args.Get(0).(string), args.Error(1)
+}
 
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..54a53f5
--- /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 (
+       "github.com/stretchr/testify/mock"
+       "rsm/models"
+)
+
+type ResourceStatusResponseConverterMock struct {
+       mock.Mock
+}
+
+func (m *ResourceStatusResponseConverterMock)Convert(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*models.ResourceStatusResponse, error){
+       args := m.Called(packedBufferSize, packedBuf, maxMessageBufferSize)
+       return args.Get(0).(*models.ResourceStatusResponse), args.Error(1)
+}
+
+func (m *ResourceStatusResponseConverterMock)UnpackX2apPduAsString(packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (string, error){
+       args := m.Called(packedBufferSize, packedBuf, maxMessageBufferSize)
+       return args.Get(0).(string), args.Error(1)
+}
+
diff --git a/RSM/models/resource_status_response.go b/RSM/models/resource_status_response.go
new file mode 100644 (file)
index 0000000..26af8de
--- /dev/null
@@ -0,0 +1,47 @@
+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())
+}
\ No newline at end of file
index 1296333..46eeff5 100644 (file)
@@ -39,18 +39,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, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, rsConverter converters.ResourceStatusResponseConverter, rsFailureConverter converters.ResourceStatusFailureConverter) *MessageHandlerProvider {
        return &MessageHandlerProvider{
-               msgHandlers: initMessageHandlersMap(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, unpacker),
+               msgHandlers: initMessageHandlersMap(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, 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, resourceStatusInitiateManager *managers.ResourceStatusInitiateManager, 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.RicResStatusFailure: rmrmsghandlers.NewResourceStatusFailureHandler(logger, rsFailureConverter),
+               rmrcgo.RicResStatusResp:    rmrmsghandlers.NewResourceStatusResponseHandler(logger, rsConverter),
        }
 }
 
index 9e7a7c2..32d644c 100644 (file)
@@ -20,6 +20,7 @@ package rmrmsghandlerprovider
 import (
        "fmt"
        "rsm/configuration"
+       "rsm/converters"
        "rsm/handlers/rmrmsghandlers"
        "rsm/managers"
        "rsm/tests/testhelper"
@@ -40,7 +41,7 @@ func TestGetNotificationHandlerSuccess(t *testing.T) {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
        resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
-
+       unpacker := converters.NewX2apPduUnpacker(logger)
        var testCases = []struct {
                msgType int
                handler rmrmsghandlers.RmrMessageHandler
@@ -50,7 +51,7 @@ func TestGetNotificationHandlerSuccess(t *testing.T) {
        }
 
        for _, tc := range testCases {
-               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+               provider := NewMessageHandlerProvider(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,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 {
@@ -75,6 +76,7 @@ func TestGetNotificationHandlerFailure(t *testing.T) {
                t.Errorf("#... - failed to parse configuration error: %s", err)
        }
        resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
+       unpacker := converters.NewX2apPduUnpacker(logger)
 
        var testCases = []struct {
                msgType   int
@@ -83,7 +85,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, resourceStatusInitiateManager,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 {
@@ -95,3 +97,4 @@ func TestGetNotificationHandlerFailure(t *testing.T) {
                })
        }
 }
+
index 1f44c8a..b9d1232 100644 (file)
@@ -20,6 +20,7 @@ package rmrreceiver
 import (
        "fmt"
        "rsm/configuration"
+       "rsm/converters"
        "rsm/logger"
        "rsm/managers"
        "rsm/managers/rmrmanagers"
@@ -58,7 +59,8 @@ func initRmrReceiver(t *testing.T) *RmrReceiver {
        resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
 
        rmrMessenger := initRmrMessenger(logger)
-       manager := rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager, nil)
+       unpacker := converters.NewX2apPduUnpacker(logger)
+       manager := rmrmanagers.NewRmrMessageManager(logger, config, rnibDataService, rmrSender, resourceStatusInitiateManager,converters.NewResourceStatusResponseConverter(unpacker), converters.NewResourceStatusFailureConverter(unpacker))
 
        return NewRmrReceiver(logger, rmrMessenger, manager)
 }