[RICPLT-1703] - Reset Request + unit tests 50/750/1
authorrh362j <ronen.hasid@intl.att.com>
Mon, 19 Aug 2019 12:25:50 +0000 (15:25 +0300)
committerrh362j <ronen.hasid@intl.att.com>
Mon, 19 Aug 2019 12:26:24 +0000 (15:26 +0300)
Change-Id: Id650f265e54d1cac230342395c6babb1073631f8
Signed-off-by: rh362j <ronen.hasid@intl.att.com>
E2Manager/container-tag.yaml
E2Manager/controllers/controller.go
E2Manager/controllers/controller_test.go
E2Manager/e2pdus/x2_reset_known_causes.go [new file with mode: 0644]
E2Manager/e2pdus/x2_reset_known_causes_test.go [new file with mode: 0644]
E2Manager/handlers/x2_reset_request_handler.go
E2Manager/handlers/x2_reset_request_handler_test.go [new file with mode: 0644]
E2Manager/handlers/x2_reset_response_handler.go

index 5c23161..daa3e14 100644 (file)
@@ -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
index 0e13d0d..7682721 100644 (file)
@@ -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
                }
index 6bc1613..4d0774e 100644 (file)
@@ -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 (file)
index 0000000..3575a12
--- /dev/null
@@ -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 <x2reset_request_wrapper.h>
+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 (file)
index 0000000..5a3d474
--- /dev/null
@@ -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
index 63484bb..f5afbaa 100644 (file)
 //
 
 package handlers
-// #cgo CFLAGS: -I../asn1codec/inc/  -I../asn1codec/e2ap_engine/
-// #cgo LDFLAGS: -L ../asn1codec/lib/ -L../asn1codec/e2ap_engine/ -le2ap_codec -lasncodec
-// #include <x2reset_request_wrapper.h>
-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 (file)
index 0000000..e59b442
--- /dev/null
@@ -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)
+}
index 7de2e2c..0fbebf3 100644 (file)
@@ -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