From 574c21e37f9e740579227c81c22253b8c7aa5404 Mon Sep 17 00:00:00 2001 From: rh362j Date: Mon, 19 Aug 2019 15:25:50 +0300 Subject: [PATCH] [RICPLT-1703] - Reset Request + unit tests Change-Id: Id650f265e54d1cac230342395c6babb1073631f8 Signed-off-by: rh362j --- E2Manager/container-tag.yaml | 2 +- E2Manager/controllers/controller.go | 20 +- E2Manager/controllers/controller_test.go | 179 ++++++++++++++ E2Manager/e2pdus/x2_reset_known_causes.go | 126 ++++++++++ E2Manager/e2pdus/x2_reset_known_causes_test.go | 88 +++++++ E2Manager/handlers/x2_reset_request_handler.go | 104 +------- .../handlers/x2_reset_request_handler_test.go | 273 +++++++++++++++++++++ E2Manager/handlers/x2_reset_response_handler.go | 33 ++- 8 files changed, 702 insertions(+), 123 deletions(-) create mode 100644 E2Manager/e2pdus/x2_reset_known_causes.go create mode 100644 E2Manager/e2pdus/x2_reset_known_causes_test.go create mode 100644 E2Manager/handlers/x2_reset_request_handler_test.go diff --git a/E2Manager/container-tag.yaml b/E2Manager/container-tag.yaml index 5c23161..daa3e14 100644 --- a/E2Manager/container-tag.yaml +++ b/E2Manager/container-tag.yaml @@ -1,4 +1,4 @@ # The Jenkins job requires a tag to build the Docker image. # Global-JJB script assumes this file is in the repo root. --- -tag: 1.0.3 +tag: 1.0.4 diff --git a/E2Manager/controllers/controller.go b/E2Manager/controllers/controller.go index 0e13d0d..7682721 100644 --- a/E2Manager/controllers/controller.go +++ b/E2Manager/controllers/controller.go @@ -28,7 +28,6 @@ import ( "encoding/json" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/julienschmidt/httprouter" - "io" "net/http" "time" ) @@ -52,15 +51,17 @@ func NewController(logger *logger.Logger, rmrService *services.RmrService, rNibR } func (c *Controller)ShutdownHandler(writer http.ResponseWriter, r *http.Request, params httprouter.Params){ - + c.logger.Infof("[Client -> E2 Manager] #controller.ShutdownHandler - request: %v", prettifyRequest(r)) c.handleRequest(writer, &r.Header, providers.ShutdownRequest,nil, false, http.StatusNoContent) } func (c *Controller) X2ResetHandler(writer http.ResponseWriter, r *http.Request, params httprouter.Params){ startTime := time.Now() + c.logger.Infof("[Client -> E2 Manager] #controller.X2ResetHandler - request: %v", prettifyRequest(r)) request:= models.ResetRequest{} ranName:= params.ByName(ParamRanName) - if !c.extractJsonBody(r.Body, &request, writer){ + + if !c.extractJsonBody(r, &request, writer){ return } request.RanName = ranName @@ -68,15 +69,20 @@ func (c *Controller) X2ResetHandler(writer http.ResponseWriter, r *http.Request, c.handleRequest(writer, &r.Header, providers.ResetRequest, request, false, http.StatusNoContent) } -func (c *Controller) extractJsonBody(body io.Reader, request models.Request, writer http.ResponseWriter) bool{ - decoder := json.NewDecoder(body) - if err:= decoder.Decode(request); err != nil { +func (c *Controller) extractJsonBody(r *http.Request, request models.Request, writer http.ResponseWriter) bool{ + if r.ContentLength <= 0 { + return true + } + + decoder := json.NewDecoder(r.Body) + if err := decoder.Decode(request); err != nil { if err != nil { c.logger.Errorf("[Client -> E2 Manager] #controller.extractJsonBody - unable to extract json body - error: %s", err) c.handleErrorResponse(e2managererrors.NewRequestValidationError(), writer) return false } } + return true } @@ -158,7 +164,7 @@ func (c *Controller) handleErrorResponse(err error, writer http.ResponseWriter){ httpError = http.StatusNotFound default: - e2Error, _ := err.(*e2managererrors.InternalError) + e2Error := e2managererrors.NewInternalError() errorResponseDetails = models.ErrorResponse{Code: e2Error.Err.Code, Message: e2Error.Err.Message} httpError = http.StatusInternalServerError } diff --git a/E2Manager/controllers/controller_test.go b/E2Manager/controllers/controller_test.go index 6bc1613..4d0774e 100644 --- a/E2Manager/controllers/controller_test.go +++ b/E2Manager/controllers/controller_test.go @@ -18,6 +18,7 @@ package controllers import ( + "bytes" "e2mgr/configuration" "e2mgr/e2managererrors" "e2mgr/logger" @@ -25,16 +26,21 @@ import ( "e2mgr/models" "e2mgr/providers" "e2mgr/rNibWriter" + "e2mgr/rmrCgo" "e2mgr/tests" "encoding/json" + "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" + "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "io" "io/ioutil" "net/http" "net/http/httptest" + "strings" "testing" ) @@ -214,3 +220,176 @@ func initLog(t *testing.T) *logger.Logger { } return log } + + +func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T){ + log := initLog(t) + + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + payload:= []byte {0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40} + xaction := []byte(ranName) + msg:= rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrMessengerMock.On("SendMsg",msg,mock.Anything).Return(msg,nil) + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + + writer := httptest.NewRecorder() + controller := NewController(log, rmrService, readerProvider, writerProvider, config) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + data4Req := map[string]interface{}{"cause": "protocol:transfer-syntax-error"} + b := new(bytes.Buffer) + _ = json.NewEncoder(b).Encode(data4Req) + req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b) + + param:= httprouter.Param{Key:"ranName", Value: ranName} + controller.X2ResetHandler(writer, req, []httprouter.Param {param}) + assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode) + + v, ok := rmrService.E2sessions[ranName] + assert.True(t, ok) + + assert.Equal(t, v.Request.RanName, ranName) +} + +func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T){ + log := initLog(t) + + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + // o&m intervention + payload:= []byte {0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} + xaction := []byte(ranName) + msg:= rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrMessengerMock.On("SendMsg",msg,mock.Anything).Return(msg,nil) + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + + writer := httptest.NewRecorder() + controller := NewController(log, rmrService, readerProvider, writerProvider, config) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + // no body + b := new(bytes.Buffer) + req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b) + + param:= httprouter.Param{Key:"ranName", Value: ranName} + controller.X2ResetHandler(writer, req, []httprouter.Param {param}) + assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode) + + v, ok := rmrService.E2sessions[ranName] + assert.True(t, ok) + + assert.Equal(t, v.Request.RanName, ranName) +} + +func TestX2ResetHandleFailureInvalidBody(t *testing.T){ + log := initLog(t) + + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + rmrMessengerMock := &mocks.RmrMessengerMock{} + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + + writer := httptest.NewRecorder() + controller := NewController(log, rmrService, readerProvider, writerProvider, config) + + // Invalid json: attribute name without quotes (should be "cause":). + b := strings.NewReader("{cause:\"protocol:transfer-syntax-error\"") + req, _ := http.NewRequest("PUT", "https://localhost:3800/nodeb-reset", b) + + param:= httprouter.Param{Key:"ranName", Value: ranName} + controller.X2ResetHandler(writer, req, []httprouter.Param {param}) + assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) + +} + +func TestHandleErrorResponse(t *testing.T){ + log := initLog(t) + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + rmrMessengerMock := &mocks.RmrMessengerMock{} + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + + + controller := NewController(log, rmrService, readerProvider, writerProvider, config) + + writer := httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewRnibDbError(),writer) + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewCommandAlreadyInProgressError(),writer) + assert.Equal(t, http.StatusMethodNotAllowed, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewHeaderValidationError(),writer) + assert.Equal(t, http.StatusUnsupportedMediaType, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewWrongStateError(""),writer) + assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewRequestValidationError(),writer) + assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewRmrError(),writer) + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(e2managererrors.NewResourceNotFoundError(),writer) + assert.Equal(t, http.StatusNotFound, writer.Result().StatusCode) + + writer = httptest.NewRecorder() + controller.handleErrorResponse(fmt.Errorf("ErrorError"),writer) + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) +} diff --git a/E2Manager/e2pdus/x2_reset_known_causes.go b/E2Manager/e2pdus/x2_reset_known_causes.go new file mode 100644 index 0000000..3575a12 --- /dev/null +++ b/E2Manager/e2pdus/x2_reset_known_causes.go @@ -0,0 +1,126 @@ +package e2pdus + +// #cgo CFLAGS: -I../asn1codec/inc/ -I../asn1codec/e2ap_engine/ +// #cgo LDFLAGS: -L ../asn1codec/lib/ -L../asn1codec/e2ap_engine/ -le2ap_codec -lasncodec +// #include +import "C" +import ( + "fmt" + "strings" + "unsafe" +) + +//TODO: replace the constant in setup_request_handler.go +const ( + MaxAsn1PackedBufferSize = 4096 + MaxAsn1CodecMessageBufferSize = 4096 +) + +// Used as default by the x2_reset_request +const ( + OmInterventionCause = "misc:om-intervention" +) + +type cause struct { + causeGroup uint32 + cause int +} + +var knownCauses = map[string]cause{ + "misc:control-processing-overload": {causeGroup: C.Cause_PR_misc, cause: C.CauseMisc_control_processing_overload}, + "misc:hardware-failure": {causeGroup: C.Cause_PR_misc, cause: C.CauseMisc_hardware_failure}, + OmInterventionCause: {causeGroup: C.Cause_PR_misc, cause: C.CauseMisc_om_intervention}, + "misc:not-enough-user-plane-processing-resources": {causeGroup: C.Cause_PR_misc, cause: C.CauseMisc_not_enough_user_plane_processing_resources}, + "misc:unspecified": {causeGroup: C.Cause_PR_misc, cause: C.CauseMisc_unspecified}, + + "protocol:transfer-syntax-error": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_transfer_syntax_error}, + "protocol:abstract-syntax-error-reject": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_reject}, + "protocol:abstract-syntax-error-ignore-and-notify": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_ignore_and_notify}, + "protocol:message-not-compatible-with-receiver-state": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_message_not_compatible_with_receiver_state}, + "protocol:semantic-error": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_semantic_error}, + "protocol:unspecified": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_unspecified}, + "protocol:abstract-syntax-error-falsely-constructed-message": {causeGroup: C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_falsely_constructed_message}, + + "transport:transport-resource-unavailable": {causeGroup: C.Cause_PR_transport, cause: C.CauseTransport_transport_resource_unavailable}, + "transport:unspecified": {causeGroup: C.Cause_PR_transport, cause: C.CauseTransport_unspecified}, + + "radioNetwork:handover-desirable-for-radio-reasons": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_handover_desirable_for_radio_reasons}, + "radioNetwork:time-critical-handover": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_time_critical_handover}, + "radioNetwork:resource-optimisation-handover": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_resource_optimisation_handover}, + "radioNetwork:reduce-load-in-serving-cell": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reduce_load_in_serving_cell}, + "radioNetwork:partial-handover": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_partial_handover}, + "radioNetwork:unknown-new-enb-ue-x2ap-id": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_new_eNB_UE_X2AP_ID}, + "radioNetwork:unknown-old-enb-ue-x2ap-id": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_old_eNB_UE_X2AP_ID}, + "radioNetwork:unknown-pair-of-ue-x2ap-id": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_pair_of_UE_X2AP_ID}, + "radioNetwork:ho-target-not-allowed": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_ho_target_not_allowed}, + "radioNetwork:tx2relocoverall-expiry": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tx2relocoverall_expiry}, + "radioNetwork:trelocprep-expiry": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_trelocprep_expiry}, + "radioNetwork:cell-not-available": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_cell_not_available}, + "radioNetwork:no-radio-resources-available-in-target-cell": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_no_radio_resources_available_in_target_cell}, + "radioNetwork:invalid-mme-groupid": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_invalid_MME_GroupID}, + "radioNetwork:unknown-mme-code": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_MME_Code}, + "radioNetwork:encryption-and-or-integrity-protection-algorithms-not-supported": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported}, + "radioNetwork:reportcharacteristicsempty": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reportCharacteristicsEmpty}, + "radioNetwork:noreportperiodicity": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_noReportPeriodicity}, + "radioNetwork:existingMeasurementID": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_existingMeasurementID}, + "radioNetwork:unknown-enb-measurement-id": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_eNB_Measurement_ID}, + "radioNetwork:measurement-temporarily-not-available": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_measurement_temporarily_not_available}, + "radioNetwork:unspecified": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unspecified}, + "radioNetwork:load-balancing": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_load_balancing}, + "radioNetwork:handover-optimisation": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_handover_optimisation}, + "radioNetwork:value-out-of-allowed-range": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_value_out_of_allowed_range}, + "radioNetwork:multiple-E-RAB-ID-instances": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_multiple_E_RAB_ID_instances}, + "radioNetwork:switch-off-ongoing": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_switch_off_ongoing}, + "radioNetwork:not-supported-qci-value": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_not_supported_QCI_value}, + "radioNetwork:measurement-not-supported-for-the-object": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_measurement_not_supported_for_the_object}, + "radioNetwork:tdcoverall-expiry": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tDCoverall_expiry}, + "radioNetwork:tdcprep-expiry": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tDCprep_expiry}, + "radioNetwork:action-desirable-for-radio-reasons": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_action_desirable_for_radio_reasons}, + "radioNetwork:reduce-load": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reduce_load}, + "radioNetwork:resource-optimisation": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_resource_optimisation}, + "radioNetwork:time-critical-action": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_time_critical_action}, + "radioNetwork:target-not-allowed": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_target_not_allowed}, + "radioNetwork:no-radio-resources-available": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_no_radio_resources_available}, + "radioNetwork:invalid-qos-combination": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_invalid_QoS_combination}, + "radioNetwork:encryption-algorithms-not-aupported": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_encryption_algorithms_not_aupported}, + "radioNetwork:procedure-cancelled": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_procedure_cancelled}, + "radioNetwork:rrm-purpose": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_rRM_purpose}, + "radioNetwork:improve-user-bit-rate": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_improve_user_bit_rate}, + "radioNetwork:user-inactivity": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_user_inactivity}, + "radioNetwork:radio-connection-with-ue-lost": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_radio_connection_with_UE_lost}, + "radioNetwork:failure-in-the-radio-interface-procedure": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_failure_in_the_radio_interface_procedure}, + "radioNetwork:bearer-option-not-supported": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_bearer_option_not_supported}, + "radioNetwork:mcg-mobility": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_mCG_Mobility}, + "radioNetwork:scg-mobility": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_sCG_Mobility}, + "radioNetwork:count-reaches-max-value": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_count_reaches_max_value}, + "radioNetwork:unknown-old-en-gnb-ue-x2ap-id": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_old_en_gNB_UE_X2AP_ID}, + "radioNetwork:pdcp-Overload": {causeGroup: C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_pDCP_Overload}, +} + +var knownCausesToX2ResetPDUs = map[string][]byte{} + +func prepareX2ResetPDUs(maxAsn1PackedBufferSize int, maxAsn1CodecMessageBufferSize int) error { + packedBuffer := make([]C.uchar,maxAsn1PackedBufferSize) + errorBuffer := make([]C.char,maxAsn1CodecMessageBufferSize) + + for k, cause := range knownCauses { + var payloadSize = C.ulong(maxAsn1PackedBufferSize) + if status := C.build_pack_x2reset_request(cause.causeGroup, C.int(cause.cause), &payloadSize, &packedBuffer[0], C.ulong(maxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { + return fmt.Errorf("#reset_request_handler.Handle - failed to build and pack the reset message %s ", C.GoString(&errorBuffer[0])) + } + knownCausesToX2ResetPDUs[strings.ToLower(k)] = C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) + } + return nil +} + +// KnownCausesToX2ResetPDU returns a packed x2 reset pdu with the specified cause (case insensitive match). +func KnownCausesToX2ResetPDU(cause string) ([]byte, bool) { + v, ok := knownCausesToX2ResetPDUs[strings.ToLower(cause)] + return v, ok +} + +func init() { + if err := prepareX2ResetPDUs(MaxAsn1PackedBufferSize, MaxAsn1CodecMessageBufferSize); err != nil { + panic(err) + } +} diff --git a/E2Manager/e2pdus/x2_reset_known_causes_test.go b/E2Manager/e2pdus/x2_reset_known_causes_test.go new file mode 100644 index 0000000..5a3d474 --- /dev/null +++ b/E2Manager/e2pdus/x2_reset_known_causes_test.go @@ -0,0 +1,88 @@ +package e2pdus + +import ( + "e2mgr/logger" + "fmt" + "strings" + "testing" +) + +func TestKnownCausesToX2ResetPDU(t *testing.T) { + _,err := logger.InitLogger(logger.InfoLevel) + if err!=nil{ + t.Errorf("failed to initialize logger, error: %s", err) + } + var testCases = []struct { + cause string + packedPdu string + }{ + { + cause: OmInterventionCause, + packedPdu: "000700080000010005400164", + }, + { + cause: "PROTOCOL:transfer-syntax-error", + packedPdu: "000700080000010005400140", + }, + { + cause: "transport:transport-RESOURCE-unavailable", + packedPdu: "000700080000010005400120", + }, + + { + cause: "radioNetwork:invalid-MME-groupid", + packedPdu: "00070009000001000540020680", + }, + + } + + for _, tc := range testCases { + t.Run(tc.packedPdu, func(t *testing.T) { + + payload, ok := KnownCausesToX2ResetPDU(tc.cause) + if !ok { + t.Errorf("want: success, got: not found.\n") + } else { + tmp := fmt.Sprintf("%x", payload) + if len(tmp) != len(tc.packedPdu) { + t.Errorf("want packed len:%d, got: %d\n", len(tc.packedPdu)/2, len(payload)/2) + } + + if strings.Compare(tmp, tc.packedPdu) != 0 { + t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", tc.packedPdu, tmp) + } + } + }) + } +} + + +func TestKnownCausesToX2ResetPDUFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + _, ok := KnownCausesToX2ResetPDU("xxxx") + if ok { + t.Errorf("want: not found, got: success.\n") + } +} + + +func TestPrepareX2ResetPDUsFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + err = prepareX2ResetPDUs(1, 4096) + if err == nil { + t.Errorf("want: error, got: success.\n") + } + + expected:= "#reset_request_handler.Handle - failed to build and pack the reset message #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big:" + if !strings.Contains(err.Error(), expected) { + t.Errorf("want :[%s], got: [%s]\n", expected, err) + } +} \ No newline at end of file diff --git a/E2Manager/handlers/x2_reset_request_handler.go b/E2Manager/handlers/x2_reset_request_handler.go index 63484bb..f5afbaa 100644 --- a/E2Manager/handlers/x2_reset_request_handler.go +++ b/E2Manager/handlers/x2_reset_request_handler.go @@ -16,14 +16,12 @@ // package handlers -// #cgo CFLAGS: -I../asn1codec/inc/ -I../asn1codec/e2ap_engine/ -// #cgo LDFLAGS: -L ../asn1codec/lib/ -L../asn1codec/e2ap_engine/ -le2ap_codec -lasncodec -// #include -import "C" import ( "e2mgr/configuration" "e2mgr/e2managererrors" + "e2mgr/e2pdus" "e2mgr/logger" + "e2mgr/models" "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" @@ -31,9 +29,6 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" - "unsafe" - - "e2mgr/models" ) type X2ResetRequestHandler struct { @@ -43,86 +38,6 @@ type X2ResetRequestHandler struct { config *configuration.Configuration } -/* - -C -*/ - -type cause struct { -causeGroup uint32 -cause int -} - -var knownCauses = map[string] cause { -"misc:control-processing-overload": {causeGroup:C.Cause_PR_misc, cause: C.CauseMisc_control_processing_overload}, -"misc:hardware-failure": {causeGroup:C.Cause_PR_misc, cause: C.CauseMisc_hardware_failure}, -"misc:om-intervention": {causeGroup:C.Cause_PR_misc, cause: C.CauseMisc_om_intervention}, -"misc:not-enough-user-plane-processing-resources": {causeGroup:C.Cause_PR_misc, cause: C.CauseMisc_not_enough_user_plane_processing_resources}, -"misc:unspecified": {causeGroup:C.Cause_PR_misc, cause: C.CauseMisc_unspecified}, - -"protocol:transfer-syntax-error": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_transfer_syntax_error}, -"protocol:abstract-syntax-error-reject": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_reject}, -"protocol:abstract-syntax-error-ignore-and-notify": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_ignore_and_notify}, -"protocol:message-not-compatible-with-receiver-state": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_message_not_compatible_with_receiver_state}, -"protocol:semantic-error": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_semantic_error}, -"protocol:unspecified": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_unspecified}, -"protocol:abstract-syntax-error-falsely-constructed-message": {causeGroup:C.Cause_PR_protocol, cause: C.CauseProtocol_abstract_syntax_error_falsely_constructed_message}, - -"transport:transport-resource-unavailable": {causeGroup:C.Cause_PR_transport, cause: C.CauseTransport_transport_resource_unavailable}, -"transport:unspecified":{causeGroup:C.Cause_PR_transport, cause: C.CauseTransport_unspecified}, - -"radioNetwork:handover-desirable-for-radio-reasons": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_handover_desirable_for_radio_reasons}, -"radioNetwork:time-critical-handover": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_time_critical_handover}, -"radioNetwork:resource-optimisation-handover": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_resource_optimisation_handover}, -"radioNetwork:reduce-load-in-serving-cell": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reduce_load_in_serving_cell}, -"radioNetwork:partial-handover": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_partial_handover}, -"radioNetwork:unknown-new-enb-ue-x2ap-id": {causeGroup:C.Cause_PR_radioNetwork, cause:C.CauseRadioNetwork_unknown_new_eNB_UE_X2AP_ID}, -"radioNetwork:unknown-old-enb-ue-x2ap-id": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_old_eNB_UE_X2AP_ID}, -"radioNetwork:unknown-pair-of-ue-x2ap-id": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_pair_of_UE_X2AP_ID}, -"radioNetwork:ho-target-not-allowed": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_ho_target_not_allowed}, -"radioNetwork:tx2relocoverall-expiry": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tx2relocoverall_expiry}, -"radioNetwork:trelocprep-expiry": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_trelocprep_expiry}, -"radioNetwork:cell-not-available": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_cell_not_available}, -"radioNetwork:no-radio-resources-available-in-target-cell": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_no_radio_resources_available_in_target_cell}, -"radioNetwork:invalid-mme-groupid": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_invalid_MME_GroupID}, -"radioNetwork:unknown-mme-code": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_MME_Code}, -"radioNetwork:encryption-and-or-integrity-protection-algorithms-not-supported": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported}, -"radioNetwork:reportcharacteristicsempty": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reportCharacteristicsEmpty}, -"radioNetwork:noreportperiodicity": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_noReportPeriodicity}, -"radioNetwork:existingMeasurementID": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_existingMeasurementID}, -"radioNetwork:unknown-enb-measurement-id": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_eNB_Measurement_ID}, -"radioNetwork:measurement-temporarily-not-available": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_measurement_temporarily_not_available}, -"radioNetwork:unspecified": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unspecified}, -"radioNetwork:load-balancing": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_load_balancing}, -"radioNetwork:handover-optimisation": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_handover_optimisation}, -"radioNetwork:value-out-of-allowed-range": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_value_out_of_allowed_range}, -"radioNetwork:multiple-E-RAB-ID-instances": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_multiple_E_RAB_ID_instances}, -"radioNetwork:switch-off-ongoing": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_switch_off_ongoing}, -"radioNetwork:not-supported-qci-value": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_not_supported_QCI_value}, -"radioNetwork:measurement-not-supported-for-the-object": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_measurement_not_supported_for_the_object}, -"radioNetwork:tdcoverall-expiry": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tDCoverall_expiry}, -"radioNetwork:tdcprep-expiry": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_tDCprep_expiry}, -"radioNetwork:action-desirable-for-radio-reasons": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_action_desirable_for_radio_reasons}, -"radioNetwork:reduce-load": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_reduce_load}, -"radioNetwork:resource-optimisation": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_resource_optimisation}, -"radioNetwork:time-critical-action": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_time_critical_action}, -"radioNetwork:target-not-allowed": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_target_not_allowed}, -"radioNetwork:no-radio-resources-available": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_no_radio_resources_available}, -"radioNetwork:invalid-qos-combination": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_invalid_QoS_combination}, -"radioNetwork:encryption-algorithms-not-aupported": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_encryption_algorithms_not_aupported}, -"radioNetwork:procedure-cancelled":{causeGroup:C.Cause_PR_radioNetwork, cause:C.CauseRadioNetwork_procedure_cancelled}, -"radioNetwork:rrm-purpose": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_rRM_purpose}, -"radioNetwork:improve-user-bit-rate": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_improve_user_bit_rate}, -"radioNetwork:user-inactivity": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_user_inactivity}, -"radioNetwork:radio-connection-with-ue-lost": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_radio_connection_with_UE_lost}, -"radioNetwork:failure-in-the-radio-interface-procedure": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_failure_in_the_radio_interface_procedure}, -"radioNetwork:bearer-option-not-supported": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_bearer_option_not_supported}, -"radioNetwork:mcg-mobility": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_mCG_Mobility}, -"radioNetwork:scg-mobility": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_sCG_Mobility}, -"radioNetwork:count-reaches-max-value": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_count_reaches_max_value}, -"radioNetwork:unknown-old-en-gnb-ue-x2ap-id": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_unknown_old_en_gNB_UE_X2AP_ID} , -"radioNetwork:pdcp-Overload": {causeGroup:C.Cause_PR_radioNetwork, cause: C.CauseRadioNetwork_pDCP_Overload}, -} func NewX2ResetRequestHandler(rmrService *services.RmrService, config *configuration.Configuration, writerProvider func() rNibWriter.RNibWriter, readerProvider func() reader.RNibReader) *X2ResetRequestHandler { @@ -138,9 +53,9 @@ func (handler *X2ResetRequestHandler) Handle(logger *logger.Logger, request mode resetRequest := request.(models.ResetRequest) if len(resetRequest.Cause) == 0 { - resetRequest.Cause = "misc:om-intervention" + resetRequest.Cause = e2pdus.OmInterventionCause } - cause, ok:= knownCauses[resetRequest.Cause] + payload, ok:= e2pdus.KnownCausesToX2ResetPDU(resetRequest.Cause) if !ok { logger.Errorf("#reset_request_handler.Handle - Unknown cause (%s)", resetRequest.Cause) return e2managererrors.NewRequestValidationError() @@ -160,19 +75,12 @@ func (handler *X2ResetRequestHandler) Handle(logger *logger.Logger, request mode return e2managererrors.NewWrongStateError(entities.ConnectionStatus_name[int32(nodeb.ConnectionStatus)]) } - var payloadSize = C.ulong(MaxAsn1PackedBufferSize) - packedBuffer := [MaxAsn1PackedBufferSize]C.uchar{} - errorBuffer := [MaxAsn1CodecMessageBufferSize]C.char{} - - if status := C.build_pack_x2reset_request(cause.causeGroup, C.int(cause.cause), &payloadSize, &packedBuffer[0], MaxAsn1CodecMessageBufferSize, &errorBuffer[0]); !status { - logger.Errorf("#reset_request_handler.Handle - failed to build and pack the reset message %s ", C.GoString(&errorBuffer[0])) - return e2managererrors.NewInternalError() - } transactionId := resetRequest.RanName handler.rmrService.E2sessions[transactionId] = sessions.E2SessionDetails{SessionStart: resetRequest.StartTime, Request: &models.RequestDetails{RanName: resetRequest.RanName}} - response := models.NotificationResponse{MgsType: rmrCgo.RIC_X2_RESET, RanName: resetRequest.RanName, Payload: C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize))} + response := models.NotificationResponse{MgsType: rmrCgo.RIC_X2_RESET, RanName: resetRequest.RanName, Payload: payload} if err:= handler.rmrService.SendRmrMessage(&response); err != nil { logger.Errorf("#reset_request_handler.Handle - failed to send reset message to RMR: %s", err) + delete(handler.rmrService.E2sessions, transactionId) return e2managererrors.NewRmrError() } diff --git a/E2Manager/handlers/x2_reset_request_handler_test.go b/E2Manager/handlers/x2_reset_request_handler_test.go new file mode 100644 index 0000000..e59b442 --- /dev/null +++ b/E2Manager/handlers/x2_reset_request_handler_test.go @@ -0,0 +1,273 @@ +package handlers + +import ( + "e2mgr/configuration" + "e2mgr/e2managererrors" + "e2mgr/mocks" + "e2mgr/models" + "e2mgr/rNibWriter" + "e2mgr/rmrCgo" + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" + "time" +) + + +func TestHandleSuccessfulDefaultCause(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + // o&m intervention + payload:= []byte {0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} + xaction := []byte(ranName) + msg:= rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrMessengerMock.On("SendMsg",msg,mock.Anything).Return(msg,nil) + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , StartTime: curTime}) + + assert.Nil(t, actual) + + v, ok := rmrService.E2sessions[ranName] + assert.True(t, ok) + + assert.Equal(t, v.Request.RanName, ranName) + + assert.Equal(t, v.SessionStart ,curTime) +} + +func TestHandleSuccessfulRequestedCause(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + + payload:= []byte {0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40} + xaction := []byte(ranName) + msg:= rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrMessengerMock.On("SendMsg",msg,mock.Anything).Return(msg,nil) + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , Cause:"protocol:transfer-syntax-error", StartTime: curTime}) + + assert.Nil(t, actual) + + v, ok := rmrService.E2sessions[ranName] + assert.True(t, ok) + + assert.Equal(t, v.Request.RanName, ranName) + + assert.Equal(t, v.SessionStart ,curTime) +} + +func TestHandleFailureUnknownCause(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + + + rmrMessengerMock := &mocks.RmrMessengerMock{} + + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , Cause:"XXX", StartTime: curTime}) + + assert.IsType(t, e2managererrors.NewRequestValidationError(), actual) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) +} + +func TestHandleFailureWrongState(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + + + rmrMessengerMock := &mocks.RmrMessengerMock{} + + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , StartTime: curTime}) + + assert.IsType(t, e2managererrors.NewWrongStateError(entities.ConnectionStatus_name[int32(nodeb.ConnectionStatus)]), actual) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) +} + + + +func TestHandleFailureRanNotFound(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + + + rmrMessengerMock := &mocks.RmrMessengerMock{} + + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + readerMock.On("GetNodeb",ranName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError(fmt.Errorf("nodeb not found"))) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , StartTime: curTime}) + + assert.IsType(t, e2managererrors.NewResourceNotFoundError(), actual) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) +} + + +func TestHandleFailureRnibError(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + + + rmrMessengerMock := &mocks.RmrMessengerMock{} + + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + readerMock.On("GetNodeb",ranName).Return(&entities.NodebInfo{}, common.NewInternalError(fmt.Errorf("internal error"))) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , StartTime: curTime}) + + assert.IsType(t, e2managererrors.NewRnibDbError(), actual) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) +} + + +func TestHandleFailureRmrError(t *testing.T){ + log := initLog(t) + + curTime := time.Now() + ranName := "test1" + + readerMock := &mocks.RnibReaderMock{} + readerProvider := func() reader.RNibReader { + return readerMock + } + writerMock := &mocks.RnibWriterMock{} + writerProvider := func() rNibWriter.RNibWriter { + return writerMock + } + // o&m intervention + payload:= []byte {0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} + xaction := []byte(ranName) + msg:= rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrMessengerMock.On("SendMsg",msg,mock.Anything).Return(&rmrCgo.MBuf{},fmt.Errorf("rmr error")) + + config := configuration.ParseConfiguration() + rmrService:=getRmrService(rmrMessengerMock, log) + handler := NewX2ResetRequestHandler(rmrService, config, writerProvider, readerProvider) + + var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED } + readerMock.On("GetNodeb",ranName).Return(nodeb, nil) + + actual := handler.Handle(log, models.ResetRequest{RanName: ranName , StartTime: curTime}) + + assert.IsType(t, e2managererrors.NewRmrError(), actual) + + _, ok := rmrService.E2sessions[ranName] + assert.False(t, ok) +} diff --git a/E2Manager/handlers/x2_reset_response_handler.go b/E2Manager/handlers/x2_reset_response_handler.go index 7de2e2c..0fbebf3 100644 --- a/E2Manager/handlers/x2_reset_response_handler.go +++ b/E2Manager/handlers/x2_reset_response_handler.go @@ -42,24 +42,23 @@ func NewX2ResetResponseHandler(rnibReaderProvider func() reader.RNibReader) X2Re func (src X2ResetResponseHandler) Handle(logger *logger.Logger, e2Sessions sessions.E2Sessions, request *models.NotificationRequest, messageChannel chan<- *models.NotificationResponse) { request.TransactionId = request.RanName - logger.Debugf("#x2ResetResponseHandler.Handle - transactionId %s: received reset response. Payload: %s", request.TransactionId, request.Payload) - if nb, rNibErr := src.rnibReaderProvider().GetNodeb(request.RanName); rNibErr != nil { - logger.Errorf("#x2ResetResponseHandler.Handle - transactionId %s: failed to retrieve nb entity. RanName: %s. Error: %s", request.TransactionId, request.RanName, rNibErr.Error()) + logger.Debugf("#x2ResetResponseHandler.Handle - transactionId %s: received reset response. Payload: %s", request.TransactionId, request.Payload) + + if nb, rNibErr := src.rnibReaderProvider().GetNodeb(request.RanName); rNibErr != nil { + logger.Errorf("#x2ResetResponseHandler.Handle - transactionId %s: failed to retrieve nb entity. RanName: %s. Error: %s", request.TransactionId, request.RanName, rNibErr.Error()) + } else { + logger.Debugf("#x2ResetResponseHandler.Handle - transactionId %s: nb entity retrieved. RanName %s, ConnectionStatus %s", request.TransactionId, nb.RanName, nb.ConnectionStatus) + refinedMessage, err := unpackX2apPduAndRefine(logger, MaxAsn1CodecAllocationBufferSize /*allocation buffer*/, request.Len, request.Payload, MaxAsn1CodecMessageBufferSize /*message buffer*/) + if err != nil { + logger.Errorf("#x2ResetResponseHandler.Handle - transactionId %s: failed to unpack reset response message. RanName %s, Payload: %s", request.TransactionId , request.RanName, request.Payload) } else { - logger.Debugf("#x2ResetResponseHandler.Handle - transactionId %s: nb entity retrieved. RanName %s, ConnectionStatus %s", request.TransactionId, nb.RanName, nb.ConnectionStatus) - //TODO: only returned in debug mode - refinedMessage, err := unpackX2apPduAndRefine(logger, MaxAsn1CodecAllocationBufferSize /*allocation buffer*/, request.Len, request.Payload, MaxAsn1CodecMessageBufferSize /*message buffer*/) - if err != nil { - logger.Errorf("#x2ResetResponseHandler.Handle - transactionId %s: failed to unpack reset response message. RanName %s, Payload: %s", request.TransactionId , request.RanName, request.Payload) - } else { - logger.Infof("#x2ResetResponseHandler.Handle - transactionId %s: reset response message payload unpacked. RanName %s, Message: %s", request.TransactionId , request.RanName, refinedMessage.pduPrint) - } - } - e2session, ok := e2Sessions[request.TransactionId] - if ok { - printHandlingSetupResponseElapsedTimeInMs(logger, fmt.Sprintf("#x2ResetResponseHandler.Handle- Summary: Total roundtrip elapsed time for transactionId %s", request.TransactionId), e2session.SessionStart) - delete(e2Sessions, request.TransactionId) + logger.Debugf("#x2ResetResponseHandler.Handle - transactionId %s: reset response message payload unpacked. RanName %s, Message: %s", request.TransactionId , request.RanName, refinedMessage.pduPrint) } - + } + e2session, ok := e2Sessions[request.TransactionId] + if ok { + printHandlingSetupResponseElapsedTimeInMs(logger, fmt.Sprintf("#x2ResetResponseHandler.Handle- Summary: Total roundtrip elapsed time for transactionId %s", request.TransactionId), e2session.SessionStart) + delete(e2Sessions, request.TransactionId) + } } \ No newline at end of file -- 2.16.6