"strconv"
)
-const MaxRnibPoolInstances = 4
-
func main() {
config, err := configuration.ParseConfiguration()
if err != nil {
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()
--- /dev/null
+/*
+ *
+ * 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 */
--- /dev/null
+//
+// 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)
+}
--- /dev/null
+/*******************************************************************************
+ *
+ * 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)
+
+ }
+}
--- /dev/null
+//
+// 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)
+}
--- /dev/null
+/*******************************************************************************
+ *
+ * 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)
+
+ }
+}
"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) {
)
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)
+ }
+}
import (
"fmt"
+ "rsm/converters"
"rsm/e2pdus"
"rsm/logger"
"rsm/mocks"
"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)
}
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)
}
--- /dev/null
+//
+// 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)
+}
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,
import (
"rsm/configuration"
+ "rsm/converters"
"rsm/managers"
"rsm/rmrcgo"
"rsm/tests/testhelper"
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")
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")
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)
+}
--- /dev/null
+//
+// 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)
+}
+
--- /dev/null
+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
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),
}
}
import (
"fmt"
"rsm/configuration"
+ "rsm/converters"
"rsm/handlers/rmrmsghandlers"
"rsm/managers"
"rsm/tests/testhelper"
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
}
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 {
t.Errorf("#... - failed to parse configuration error: %s", err)
}
resourceStatusInitiateManager := managers.NewResourceStatusInitiateManager(logger, rnibDataService, rmrSender)
+ unpacker := converters.NewX2apPduUnpacker(logger)
var testCases = []struct {
msgType int
{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 {
})
}
}
+
import (
"fmt"
"rsm/configuration"
+ "rsm/converters"
"rsm/logger"
"rsm/managers"
"rsm/managers/rmrmanagers"
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)
}