From 3944a22bb267f649fff113682a6ba4253007392d Mon Sep 17 00:00:00 2001 From: Juha Hyttinen Date: Fri, 24 Jan 2020 11:51:46 +0200 Subject: [PATCH] RICPLT-3015 Reusing subscription if same EventTrigger and Action Change-Id: Ibda45d0864ce1626fb3973519a799a69579e7614 Signed-off-by: Juha Hyttinen --- pkg/control/client.go | 4 +- pkg/control/control.go | 57 ++++-- pkg/control/registry.go | 95 +++++++--- pkg/control/subscription.go | 80 ++++++++ pkg/control/ut_ctrl_submgr_test.go | 14 ++ pkg/control/ut_messaging_test.go | 377 ++++++++++++++++++++++++++++++++++--- pkg/control/ut_stub_rtmgr_test.go | 27 ++- pkg/control/ut_stub_xapp_test.go | 72 ++++--- 8 files changed, 621 insertions(+), 105 deletions(-) diff --git a/pkg/control/client.go b/pkg/control/client.go index 4146428..73e2ee0 100644 --- a/pkg/control/client.go +++ b/pkg/control/client.go @@ -66,9 +66,9 @@ func (rc *RtmgrClient) SubscriptionRequestUpdate(subRouteAction SubRouteInfo) er deleteHandle.WithXappSubscriptionData(&deleteData) _, _, err = rc.rtClient.Handle.DeleteXappSubscriptionHandle(deleteHandle) case UPDATE: - updateData := rtmgr_models.XappList{} + var updateData rtmgr_models.XappList for i := range subRouteAction.EpList.Endpoints { - updateData[i] = &rtmgr_models.XappElement{Address: &subRouteAction.EpList.Endpoints[i].Addr, Port: &subRouteAction.EpList.Endpoints[i].Port} + updateData = append(updateData, &rtmgr_models.XappElement{Address: &subRouteAction.EpList.Endpoints[i].Addr, Port: &subRouteAction.EpList.Endpoints[i].Port}) } updateHandle := rtmgrhandle.NewUpdateXappSubscriptionHandleParamsWithTimeout(10 * time.Second) updateHandle.WithSubscriptionID(subRouteAction.SubID) diff --git a/pkg/control/control.go b/pkg/control/control.go index c2b33b7..dee7e65 100755 --- a/pkg/control/control.go +++ b/pkg/control/control.go @@ -216,12 +216,6 @@ func (c *Control) handleXAPPSubscriptionRequest(params *RMRParams) { return } - if subs.IsTransactionReserved() { - err := fmt.Errorf("Currently parallel or queued transactions are not allowed") - xapp.Logger.Error("XAPP-SubReq: %s", idstring(trans, subs, err)) - return - } - // // Wake subs request // @@ -275,12 +269,6 @@ func (c *Control) handleXAPPSubscriptionDeleteRequest(params *RMRParams) { return } - if subs.IsTransactionReserved() { - err := fmt.Errorf("Currently parallel or queued transactions are not allowed") - xapp.Logger.Error("XAPP-SubDelReq: %s", idstring(trans, subs, err)) - return - } - // // Wake subs delete // @@ -310,23 +298,47 @@ func (c *Control) handleSubscriptionCreate(subs *Subscription, parentTrans *Tran xapp.Logger.Debug("SUBS-SubReq: Handling %s parent %s", idstring(trans, subs, nil), parentTrans.String()) + subs.mutex.Lock() if subs.SubRespMsg != nil { - xapp.Logger.Debug("SUBS-SubReq: Handling (immediate response) %s parent %s", idstring(nil, subs, nil), parentTrans.String()) + xapp.Logger.Debug("SUBS-SubReq: Handling (immediate resp response) %s parent %s", idstring(nil, subs, nil), parentTrans.String()) parentTrans.SendEvent(subs.SubRespMsg, 0) + subs.mutex.Unlock() + return + } + if subs.SubFailMsg != nil { + xapp.Logger.Debug("SUBS-SubReq: Handling (immediate fail response) %s parent %s", idstring(nil, subs, nil), parentTrans.String()) + parentTrans.SendEvent(subs.SubFailMsg, 0) + subs.mutex.Unlock() + go c.registry.RemoveFromSubscription(subs, parentTrans, 5*time.Second) return } + if subs.valid == false { + xapp.Logger.Debug("SUBS-SubReq: Handling (immediate nil response) %s parent %s", idstring(nil, subs, nil), parentTrans.String()) + parentTrans.SendEvent(nil, 0) + subs.mutex.Unlock() + go c.registry.RemoveFromSubscription(subs, parentTrans, 5*time.Second) + return + } + subs.mutex.Unlock() event := c.sendE2TSubscriptionRequest(subs, trans, parentTrans) switch themsg := event.(type) { case *e2ap.E2APSubscriptionResponse: + subs.mutex.Lock() subs.SubRespMsg = themsg + subs.mutex.Unlock() parentTrans.SendEvent(event, 0) return case *e2ap.E2APSubscriptionFailure: - //TODO: Possible delete and one retry for subs req + subs.mutex.Lock() + subs.SubFailMsg = themsg + subs.mutex.Unlock() parentTrans.SendEvent(event, 0) default: xapp.Logger.Info("SUBS-SubReq: internal delete due event(%s) %s", typeofSubsMessage(event), idstring(trans, subs, nil)) + subs.mutex.Lock() + subs.valid = false + subs.mutex.Unlock() c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans) parentTrans.SendEvent(nil, 0) } @@ -337,6 +349,7 @@ func (c *Control) handleSubscriptionCreate(subs *Subscription, parentTrans *Tran //------------------------------------------------------------------- // SUBS DELETE Handling //------------------------------------------------------------------- + func (c *Control) handleSubscriptionDelete(subs *Subscription, parentTrans *Transaction) { trans := c.tracker.NewTransaction(subs.GetMeid()) @@ -346,9 +359,21 @@ func (c *Control) handleSubscriptionDelete(subs *Subscription, parentTrans *Tran xapp.Logger.Debug("SUBS-SubDelReq: Handling %s parent %s", idstring(trans, subs, nil), parentTrans.String()) - event := c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans) + subs.mutex.Lock() + if subs.valid && subs.EpList.HasEndpoint(parentTrans.GetEndpoint()) && subs.EpList.Size() == 1 { + subs.valid = false + subs.mutex.Unlock() + c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans) + } else { + subs.mutex.Unlock() + } + + subDelRespMsg := &e2ap.E2APSubscriptionDeleteResponse{} + subDelRespMsg.RequestId.Id = subs.SubReqMsg.RequestId.Id + subDelRespMsg.RequestId.Seq = uint32(subs.GetSubId()) + subDelRespMsg.FunctionId = subs.SubReqMsg.FunctionId + parentTrans.SendEvent(subDelRespMsg, 0) - parentTrans.SendEvent(event, 0) go c.registry.RemoveFromSubscription(subs, parentTrans, 5*time.Second) } diff --git a/pkg/control/registry.go b/pkg/control/registry.go index 2750b78..6abdcdb 100644 --- a/pkg/control/registry.go +++ b/pkg/control/registry.go @@ -45,29 +45,74 @@ func (r *Registry) Initialize() { } } -func (r *Registry) AssignToSubscription(trans *Transaction, subReqMsg *e2ap.E2APSubscriptionRequest) (*Subscription, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - var sequenceNumber uint16 - - // - // Allocate subscription - // +func (r *Registry) allocateSubs(trans *Transaction, subReqMsg *e2ap.E2APSubscriptionRequest) (*Subscription, error) { if len(r.subIds) > 0 { - sequenceNumber = r.subIds[0] + sequenceNumber := r.subIds[0] r.subIds = r.subIds[1:] if _, ok := r.register[sequenceNumber]; ok == true { r.subIds = append(r.subIds, sequenceNumber) - return nil, fmt.Errorf("Registry: Failed to reserves subscription") + return nil, fmt.Errorf("Registry: Failed to reserve subscription exists") } - } else { - return nil, fmt.Errorf("Registry: Failed to reserves subscription no free ids") + subs := &Subscription{ + registry: r, + Seq: sequenceNumber, + Meid: trans.Meid, + SubReqMsg: subReqMsg, + valid: true, + } + + if subs.EpList.AddEndpoint(trans.GetEndpoint()) == false { + r.subIds = append(r.subIds, subs.Seq) + return nil, fmt.Errorf("Registry: Endpoint existing already in subscription") + } + + return subs, nil } - subs := &Subscription{ - registry: r, - Seq: sequenceNumber, - Meid: trans.Meid, + return nil, fmt.Errorf("Registry: Failed to reserve subscription no free ids") +} + +func (r *Registry) findExistingSubs(trans *Transaction, subReqMsg *e2ap.E2APSubscriptionRequest) *Subscription { + for _, subs := range r.register { + if subs.IsSame(trans, subReqMsg) { + + // + // check if there has been race conditions + // + subs.mutex.Lock() + //subs has been set to invalid + if subs.valid == false { + subs.mutex.Unlock() + continue + } + // try to add to endpointlist. + if subs.EpList.AddEndpoint(trans.GetEndpoint()) == false { + subs.mutex.Unlock() + continue + } + subs.mutex.Unlock() + + //Race collision during parallel incoming and deleted + xapp.Logger.Debug("Registry: Identical subs found %s for %s", subs.String(), trans.String()) + return subs + } + } + return nil +} + +func (r *Registry) AssignToSubscription(trans *Transaction, subReqMsg *e2ap.E2APSubscriptionRequest) (*Subscription, error) { + var err error + var newAlloc bool + r.mutex.Lock() + defer r.mutex.Unlock() + + subs := r.findExistingSubs(trans, subReqMsg) + + if subs == nil { + subs, err = r.allocateSubs(trans, subReqMsg) + if err != nil { + return nil, err + } + newAlloc = true } // @@ -76,17 +121,12 @@ func (r *Registry) AssignToSubscription(trans *Transaction, subReqMsg *e2ap.E2AP subs.mutex.Lock() defer subs.mutex.Unlock() - if subs.EpList.AddEndpoint(trans.GetEndpoint()) == false { - r.subIds = append(r.subIds, sequenceNumber) - return nil, fmt.Errorf("Registry: Endpoint existing already in subscription") - } epamount := subs.EpList.Size() r.mutex.Unlock() // // Subscription route updates // - var err error if epamount == 1 { subRouteAction := SubRouteInfo{CREATE, subs.EpList, subs.Seq} err = r.rtmgrClient.SubscriptionRequestUpdate(subRouteAction) @@ -97,18 +137,23 @@ func (r *Registry) AssignToSubscription(trans *Transaction, subReqMsg *e2ap.E2AP r.mutex.Lock() if err != nil { - r.subIds = append(r.subIds, sequenceNumber) + if newAlloc { + r.subIds = append(r.subIds, subs.Seq) + } return nil, err } - subs.SubReqMsg = subReqMsg - r.register[sequenceNumber] = subs + if newAlloc { + r.register[subs.Seq] = subs + } xapp.Logger.Debug("Registry: Create %s", subs.String()) xapp.Logger.Debug("Registry: substable=%v", r.register) return subs, nil } +// TODO: Needs better logic when there is concurrent calls func (r *Registry) RemoveFromSubscription(subs *Subscription, trans *Transaction, waitRouteClean time.Duration) error { + r.mutex.Lock() defer r.mutex.Unlock() subs.mutex.Lock() diff --git a/pkg/control/subscription.go b/pkg/control/subscription.go index 45c13ec..5bfe2e1 100644 --- a/pkg/control/subscription.go +++ b/pkg/control/subscription.go @@ -31,6 +31,7 @@ import ( //----------------------------------------------------------------------------- type Subscription struct { mutex sync.Mutex // Lock + valid bool // valid registry *Registry // Registry Seq uint16 // SubsId Meid *xapp.RMRMeid // Meid/ RanName @@ -39,6 +40,7 @@ type Subscription struct { TheTrans *Transaction // Ongoing transaction from xapp SubReqMsg *e2ap.E2APSubscriptionRequest // Subscription information SubRespMsg *e2ap.E2APSubscriptionResponse // Subscription information + SubFailMsg *e2ap.E2APSubscriptionFailure // Subscription information } func (s *Subscription) String() string { @@ -91,3 +93,81 @@ func (s *Subscription) ReleaseTransactionTurn(trans *Transaction) { s.mutex.Unlock() s.TransLock.Unlock() } + +func (s *Subscription) IsSame(trans *Transaction, subReqMsg *e2ap.E2APSubscriptionRequest) bool { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.valid == false { + return false + } + + if s.SubReqMsg == nil { + return false + } + + if s.Meid.RanName != trans.Meid.RanName { + return false + } + + if s.EpList.Size() == 0 { + return false + } + + //Somehow special case ... ? + if s.EpList.HasEndpoint(trans.GetEndpoint()) == true { + return false + } + + // EventTrigger check + if s.SubReqMsg.EventTriggerDefinition.InterfaceDirection != subReqMsg.EventTriggerDefinition.InterfaceDirection || + s.SubReqMsg.EventTriggerDefinition.ProcedureCode != subReqMsg.EventTriggerDefinition.ProcedureCode || + s.SubReqMsg.EventTriggerDefinition.TypeOfMessage != subReqMsg.EventTriggerDefinition.TypeOfMessage { + return false + } + + if s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[0] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[0] || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[1] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[1] || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[2] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[2] { + return false + } + + if s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.Present != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.Present || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.NodeId != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.NodeId || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[0] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[0] || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[1] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[1] || + s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[2] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[2] { + return false + } + + // Actions check + if len(s.SubReqMsg.ActionSetups) != len(subReqMsg.ActionSetups) { + return false + } + + for _, acts := range s.SubReqMsg.ActionSetups { + for _, actt := range subReqMsg.ActionSetups { + if acts.ActionId != actt.ActionId { + return false + } + if acts.ActionType != actt.ActionType { + return false + } + + if acts.ActionDefinition.Present != actt.ActionDefinition.Present || + acts.ActionDefinition.StyleId != actt.ActionDefinition.StyleId || + acts.ActionDefinition.ParamId != actt.ActionDefinition.ParamId { + return false + } + if acts.SubsequentAction.Present != actt.SubsequentAction.Present || + acts.SubsequentAction.Type != actt.SubsequentAction.Type || + acts.SubsequentAction.TimetoWait != actt.SubsequentAction.TimetoWait { + return false + } + } + } + + return true +} diff --git a/pkg/control/ut_ctrl_submgr_test.go b/pkg/control/ut_ctrl_submgr_test.go index 197eb43..8403c93 100644 --- a/pkg/control/ut_ctrl_submgr_test.go +++ b/pkg/control/ut_ctrl_submgr_test.go @@ -43,6 +43,20 @@ func createSubmgrControl(desc string, rtfile string, port string) *testingSubmgr return mainCtrl } +func (mc *testingSubmgrControl) wait_registry_empty(t *testing.T, secs int) bool { + cnt := int(0) + i := 1 + for ; i <= secs*2; i++ { + cnt = len(mc.c.registry.register) + if cnt == 0 { + return true + } + time.Sleep(500 * time.Millisecond) + } + testError(t, "(general) no registry empty within %d secs: %d", secs, cnt) + return false +} + func (mc *testingSubmgrControl) wait_subs_clean(t *testing.T, e2SubsId int, secs int) bool { var subs *Subscription i := 1 diff --git a/pkg/control/ut_messaging_test.go b/pkg/control/ut_messaging_test.go index 3b43c3a..40207b3 100644 --- a/pkg/control/ut_messaging_test.go +++ b/pkg/control/ut_messaging_test.go @@ -52,7 +52,7 @@ func TestSubReqAndRouteNok(t *testing.T) { waiter := rtmgrHttp.AllocNextEvent(false) newSubsId := mainCtrl.get_subid(t) - xappConn1.handle_xapp_subs_req(t, nil) + xappConn1.handle_xapp_subs_req(t, nil, nil) waiter.WaitResult(t) //Wait that subs is cleaned @@ -61,6 +61,7 @@ func TestSubReqAndRouteNok(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -101,7 +102,7 @@ func TestSubReqAndSubDelOk(t *testing.T) { xapp.Logger.Info("TestSubReqAndSubDelOk") waiter := rtmgrHttp.AllocNextEvent(true) - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) waiter.WaitResult(t) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) @@ -121,6 +122,7 @@ func TestSubReqAndSubDelOk(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -155,11 +157,11 @@ func TestSubReqRetransmission(t *testing.T) { xapp.Logger.Info("TestSubReqRetransmission") //Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) seqBef := mainCtrl.get_msgcounter(t) - xappConn1.handle_xapp_subs_req(t, cretrans) //Retransmitted SubReq + xappConn1.handle_xapp_subs_req(t, nil, cretrans) //Retransmitted SubReq mainCtrl.wait_msgcounter_change(t, seqBef, 10) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) @@ -177,6 +179,7 @@ func TestSubReqRetransmission(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -212,7 +215,7 @@ func TestSubDelReqRetransmission(t *testing.T) { xapp.Logger.Info("TestSubDelReqRetransmission") //Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) e2SubsId := xappConn1.handle_xapp_subs_resp(t, cretrans) @@ -234,6 +237,7 @@ func TestSubDelReqRetransmission(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -247,44 +251,53 @@ func TestSubDelReqRetransmission(t *testing.T) { // | [SUBS CREATE] | // | | | // | | | -// | SubDelReq | | +// | SubDelReq 1 | | // |------------->| | // | | | -// | | SubDelReq | +// | | SubDelReq 1 | // | |------------->| // | | | -// | SubDelReq | | +// | SubDelReq 2 | | // | (same sub) | | // | (diff xid) | | // |------------->| | // | | | -// | | SubDelResp | +// | | SubDelResp 1 | // | |<-------------| // | | | -// | SubDelResp | | +// | SubDelResp 1 | | +// |<-------------| | +// | | | +// | SubDelResp 2 | | // |<-------------| | // //----------------------------------------------------------------------------- + func TestSubDelReqCollision(t *testing.T) { xapp.Logger.Info("TestSubDelReqCollision") //Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) e2SubsId := xappConn1.handle_xapp_subs_resp(t, cretrans) //Subs Delete - deltrans := xappConn1.handle_xapp_subs_del_req(t, nil, e2SubsId) - delreq, delmsg := e2termConn.handle_e2term_subs_del_req(t) + xappConn1.handle_xapp_subs_del_req(t, nil, e2SubsId) + delreq1, delmsg1 := e2termConn.handle_e2term_subs_del_req(t) + // Subs Delete colliding seqBef := mainCtrl.get_msgcounter(t) - deltranscol := xappConn1.newXappTransaction(nil, "RAN_NAME_1") - xappConn1.handle_xapp_subs_del_req(t, deltranscol, e2SubsId) //Colliding SubDelReq + deltranscol2 := xappConn1.newXappTransaction(nil, "RAN_NAME_1") + xappConn1.handle_xapp_subs_del_req(t, deltranscol2, e2SubsId) //Colliding SubDelReq mainCtrl.wait_msgcounter_change(t, seqBef, 10) - e2termConn.handle_e2term_subs_del_resp(t, delreq, delmsg) - xappConn1.handle_xapp_subs_del_resp(t, deltrans) + // Del resp for first and second + e2termConn.handle_e2term_subs_del_resp(t, delreq1, delmsg1) + + // don't care in which order responses are received + xappConn1.handle_xapp_subs_del_resp(t, nil) + xappConn1.handle_xapp_subs_del_resp(t, nil) //Wait that subs is cleaned mainCtrl.wait_subs_clean(t, e2SubsId, 10) @@ -292,6 +305,7 @@ func TestSubDelReqCollision(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -336,11 +350,17 @@ func TestSubReqAndSubDelOkTwoParallel(t *testing.T) { xapp.Logger.Info("TestSubReqAndSubDelOkTwoParallel") //Req1 - cretrans1 := xappConn1.handle_xapp_subs_req(t, nil) + rparams1 := &test_subs_req_params{} + rparams1.Init() + rparams1.req.EventTriggerDefinition.ProcedureCode = 5 + cretrans1 := xappConn1.handle_xapp_subs_req(t, rparams1, nil) crereq1, cremsg1 := e2termConn.handle_e2term_subs_req(t) //Req2 - cretrans2 := xappConn2.handle_xapp_subs_req(t, nil) + rparams2 := &test_subs_req_params{} + rparams2.Init() + rparams2.req.EventTriggerDefinition.ProcedureCode = 28 + cretrans2 := xappConn2.handle_xapp_subs_req(t, rparams2, nil) crereq2, cremsg2 := e2termConn.handle_e2term_subs_req(t) //Resp1 @@ -370,6 +390,7 @@ func TestSubReqAndSubDelOkTwoParallel(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -418,14 +439,14 @@ func TestSameSubsDiffRan(t *testing.T) { //Req1 cretrans1 := xappConn1.newXappTransaction(nil, "RAN_NAME_1") - xappConn1.handle_xapp_subs_req(t, cretrans1) + xappConn1.handle_xapp_subs_req(t, nil, cretrans1) crereq1, cremsg1 := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq1, cremsg1) e2SubsId1 := xappConn1.handle_xapp_subs_resp(t, cretrans1) //Req2 cretrans2 := xappConn1.newXappTransaction(nil, "RAN_NAME_2") - xappConn1.handle_xapp_subs_req(t, cretrans2) + xappConn1.handle_xapp_subs_req(t, nil, cretrans2) crereq2, cremsg2 := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq2, cremsg2) e2SubsId2 := xappConn1.handle_xapp_subs_resp(t, cretrans2) @@ -451,6 +472,7 @@ func TestSameSubsDiffRan(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -487,7 +509,7 @@ func TestSubReqRetryInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubReqRetryInSubmgr start") // Xapp: Send SubsReq - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) // E2t: Receive 1st SubsReq e2termConn.handle_e2term_subs_req(t) @@ -510,6 +532,7 @@ func TestSubReqRetryInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -549,7 +572,7 @@ func TestSubReqRetryNoRespSubDelRespInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubReqTwoRetriesNoRespSubDelRespInSubmgr start") // Xapp: Send SubsReq - xappConn1.handle_xapp_subs_req(t, nil) + xappConn1.handle_xapp_subs_req(t, nil, nil) // E2t: Receive 1st SubsReq e2termConn.handle_e2term_subs_req(t) @@ -567,6 +590,7 @@ func TestSubReqRetryNoRespSubDelRespInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -603,7 +627,7 @@ func TestSubReqTwoRetriesNoRespAtAllInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubReqTwoRetriesNoRespAtAllInSubmgr start") // Xapp: Send SubsReq - xappConn1.handle_xapp_subs_req(t, nil) + xappConn1.handle_xapp_subs_req(t, nil, nil) // E2t: Receive 1st SubsReq e2termConn.handle_e2term_subs_req(t) @@ -623,6 +647,7 @@ func TestSubReqTwoRetriesNoRespAtAllInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -653,7 +678,7 @@ func TestSubReqSubFailRespInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubReqSubFailRespInSubmgr start") // Xapp: Send SubsReq - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) // E2t: Receive SubsReq and send SubsFail crereq, cremsg := e2termConn.handle_e2term_subs_req(t) @@ -670,6 +695,7 @@ func TestSubReqSubFailRespInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -705,7 +731,7 @@ func TestSubDelReqRetryInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubDelReqRetryInSubmgr start") // Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) e2SubsId := xappConn1.handle_xapp_subs_resp(t, cretrans) @@ -730,6 +756,7 @@ func TestSubDelReqRetryInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -763,7 +790,7 @@ func TestSubDelReqTwoRetriesNoRespInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubDelReTwoRetriesNoRespInSubmgr start") // Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) e2SubsId := xappConn1.handle_xapp_subs_resp(t, cretrans) @@ -787,6 +814,7 @@ func TestSubDelReqTwoRetriesNoRespInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) } //----------------------------------------------------------------------------- @@ -820,7 +848,7 @@ func TestSubDelReqSubDelFailRespInSubmgr(t *testing.T) { xapp.Logger.Info("TestSubReqSubDelFailRespInSubmgr start") // Subs Create - cretrans := xappConn1.handle_xapp_subs_req(t, nil) + cretrans := xappConn1.handle_xapp_subs_req(t, nil, nil) crereq, cremsg := e2termConn.handle_e2term_subs_req(t) e2termConn.handle_e2term_subs_resp(t, crereq, cremsg) e2SubsId := xappConn1.handle_xapp_subs_resp(t, cretrans) @@ -841,4 +869,297 @@ func TestSubDelReqSubDelFailRespInSubmgr(t *testing.T) { xappConn1.TestMsgCnt(t) xappConn2.TestMsgCnt(t) e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) +} + +//----------------------------------------------------------------------------- +// TestSubReqAndSubDelOkSameAction +// +// stub stub +// +-------+ +---------+ +---------+ +// | xapp | | submgr | | e2term | +// +-------+ +---------+ +---------+ +// | | | +// | | | +// | | | +// | SubReq1 | | +// |------------->| | +// | | | +// | | SubReq1 | +// | |------------->| +// | | SubResp1 | +// | |<-------------| +// | SubResp1 | | +// |<-------------| | +// | | | +// | SubReq2 | | +// |------------->| | +// | | | +// | SubResp2 | | +// |<-------------| | +// | | | +// | SubDelReq 1 | | +// |------------->| | +// | | | +// | SubDelResp 1 | | +// |<-------------| | +// | | | +// | SubDelReq 2 | | +// |------------->| | +// | | | +// | | SubDelReq 2 | +// | |------------->| +// | | | +// | | SubDelReq 2 | +// | |------------->| +// | | | +// | SubDelResp 2 | | +// |<-------------| | +// +//----------------------------------------------------------------------------- +func TestSubReqAndSubDelOkSameAction(t *testing.T) { + xapp.Logger.Info("TestSubReqAndSubDelOkSameAction") + + //Req1 + rparams1 := &test_subs_req_params{} + rparams1.Init() + cretrans1 := xappConn1.handle_xapp_subs_req(t, rparams1, nil) + crereq1, cremsg1 := e2termConn.handle_e2term_subs_req(t) + e2termConn.handle_e2term_subs_resp(t, crereq1, cremsg1) + e2SubsId1 := xappConn1.handle_xapp_subs_resp(t, cretrans1) + + //Req2 + rparams2 := &test_subs_req_params{} + rparams2.Init() + cretrans2 := xappConn2.handle_xapp_subs_req(t, rparams2, nil) + //crereq2, cremsg2 := e2termConn.handle_e2term_subs_req(t) + //e2termConn.handle_e2term_subs_resp(t, crereq2, cremsg2) + e2SubsId2 := xappConn2.handle_xapp_subs_resp(t, cretrans2) + + //Del1 + deltrans1 := xappConn1.handle_xapp_subs_del_req(t, nil, e2SubsId1) + //e2termConn.handle_e2term_subs_del_req(t) + //e2termConn.handle_e2term_subs_del_resp(t, delreq1, delmsg1) + xappConn1.handle_xapp_subs_del_resp(t, deltrans1) + //Wait that subs is cleaned + //mainCtrl.wait_subs_clean(t, e2SubsId1, 10) + + //Del2 + deltrans2 := xappConn2.handle_xapp_subs_del_req(t, nil, e2SubsId2) + delreq2, delmsg2 := e2termConn.handle_e2term_subs_del_req(t) + e2termConn.handle_e2term_subs_del_resp(t, delreq2, delmsg2) + xappConn2.handle_xapp_subs_del_resp(t, deltrans2) + //Wait that subs is cleaned + mainCtrl.wait_subs_clean(t, e2SubsId2, 10) + + xappConn1.TestMsgCnt(t) + xappConn2.TestMsgCnt(t) + e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) +} + +//----------------------------------------------------------------------------- +// TestSubReqAndSubDelOkSameActionParallel +// +// stub stub +// +-------+ +---------+ +---------+ +// | xapp | | submgr | | e2term | +// +-------+ +---------+ +---------+ +// | | | +// | | | +// | | | +// | SubReq1 | | +// |------------->| | +// | | | +// | | SubReq1 | +// | |------------->| +// | SubReq2 | | +// |------------->| | +// | | SubResp1 | +// | |<-------------| +// | SubResp1 | | +// |<-------------| | +// | | | +// | SubResp2 | | +// |<-------------| | +// | | | +// | SubDelReq 1 | | +// |------------->| | +// | | | +// | SubDelResp 1 | | +// |<-------------| | +// | | | +// | SubDelReq 2 | | +// |------------->| | +// | | | +// | | SubDelReq 2 | +// | |------------->| +// | | | +// | | SubDelReq 2 | +// | |------------->| +// | | | +// | SubDelResp 2 | | +// |<-------------| | +// +//----------------------------------------------------------------------------- +func TestSubReqAndSubDelOkSameActionParallel(t *testing.T) { + xapp.Logger.Info("TestSubReqAndSubDelOkSameActionParallel") + + //Req1 + rparams1 := &test_subs_req_params{} + rparams1.Init() + cretrans1 := xappConn1.handle_xapp_subs_req(t, rparams1, nil) + crereq1, cremsg1 := e2termConn.handle_e2term_subs_req(t) + + //Req2 + rparams2 := &test_subs_req_params{} + rparams2.Init() + cretrans2 := xappConn2.handle_xapp_subs_req(t, rparams2, nil) + + //Resp1 + e2termConn.handle_e2term_subs_resp(t, crereq1, cremsg1) + e2SubsId1 := xappConn1.handle_xapp_subs_resp(t, cretrans1) + + //Resp2 + e2SubsId2 := xappConn2.handle_xapp_subs_resp(t, cretrans2) + + //Del1 + deltrans1 := xappConn1.handle_xapp_subs_del_req(t, nil, e2SubsId1) + xappConn1.handle_xapp_subs_del_resp(t, deltrans1) + + //Del2 + deltrans2 := xappConn2.handle_xapp_subs_del_req(t, nil, e2SubsId2) + delreq2, delmsg2 := e2termConn.handle_e2term_subs_del_req(t) + e2termConn.handle_e2term_subs_del_resp(t, delreq2, delmsg2) + xappConn2.handle_xapp_subs_del_resp(t, deltrans2) + + //Wait that subs is cleaned + mainCtrl.wait_subs_clean(t, e2SubsId2, 10) + + xappConn1.TestMsgCnt(t) + xappConn2.TestMsgCnt(t) + e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) +} + +//----------------------------------------------------------------------------- +// TestSubReqAndSubDelNokSameActionParallel +// +// stub stub +// +-------+ +---------+ +---------+ +// | xapp | | submgr | | e2term | +// +-------+ +---------+ +---------+ +// | | | +// | | | +// | | | +// | SubReq1 | | +// |------------->| | +// | | | +// | | SubReq1 | +// | |------------->| +// | SubReq2 | | +// |------------->| | +// | | SubFail1 | +// | |<-------------| +// | SubFail1 | | +// |<-------------| | +// | | | +// | SubFail2 | | +// |<-------------| | +// +//----------------------------------------------------------------------------- +func TestSubReqAndSubDelNokSameActionParallel(t *testing.T) { + xapp.Logger.Info("TestSubReqAndSubDelNokSameActionParallel") + + //Req1 + rparams1 := &test_subs_req_params{} + rparams1.Init() + cretrans1 := xappConn1.handle_xapp_subs_req(t, rparams1, nil) + crereq1, cremsg1 := e2termConn.handle_e2term_subs_req(t) + + //Req2 + rparams2 := &test_subs_req_params{} + rparams2.Init() + seqBef2 := mainCtrl.get_msgcounter(t) + cretrans2 := xappConn2.handle_xapp_subs_req(t, rparams2, nil) + mainCtrl.wait_msgcounter_change(t, seqBef2, 10) + + //E2T Fail + fparams := &test_subs_fail_params{} + fparams.Set(crereq1) + e2termConn.handle_e2term_subs_fail(t, fparams, cremsg1) + + //Fail1 + e2SubsId1 := xappConn1.handle_xapp_subs_fail(t, cretrans1) + //Fail2 + xappConn2.handle_xapp_subs_fail(t, cretrans2) + + //Wait that subs is cleaned + mainCtrl.wait_subs_clean(t, e2SubsId1, 15) + + xappConn1.TestMsgCnt(t) + xappConn2.TestMsgCnt(t) + e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 10) +} + +//----------------------------------------------------------------------------- +// TestSubReqAndSubDelNoAnswerSameActionParallel +// +// stub stub +// +-------+ +---------+ +---------+ +// | xapp | | submgr | | e2term | +// +-------+ +---------+ +---------+ +// | | | +// | | | +// | | | +// | SubReq1 | | +// |------------->| | +// | | | +// | | SubReq1 | +// | |------------->| +// | SubReq2 | | +// |------------->| | +// | | | +// | | SubReq1 | +// | |------------->| +// | | | +// | | | +// | | SubDelReq | +// | |------------->| +// | | | +// | | SubDelResp | +// | |<-------------| +// +//----------------------------------------------------------------------------- +func TestSubReqAndSubDelNoAnswerSameActionParallel(t *testing.T) { + xapp.Logger.Info("TestSubReqAndSubDelNoAnswerSameActionParallel") + + //Req1 + rparams1 := &test_subs_req_params{} + rparams1.Init() + xappConn1.handle_xapp_subs_req(t, rparams1, nil) + + e2termConn.handle_e2term_subs_req(t) + + //Req2 + rparams2 := &test_subs_req_params{} + rparams2.Init() + seqBef2 := mainCtrl.get_msgcounter(t) + xappConn2.handle_xapp_subs_req(t, rparams2, nil) + mainCtrl.wait_msgcounter_change(t, seqBef2, 10) + + //Req1 (retransmitted) + e2termConn.handle_e2term_subs_req(t) + + delreq1, delmsg1 := e2termConn.handle_e2term_subs_del_req(t) + e2termConn.handle_e2term_subs_del_resp(t, delreq1, delmsg1) + + //Wait that subs is cleaned + mainCtrl.wait_subs_clean(t, int(delreq1.RequestId.Seq), 10) + + xappConn1.TestMsgCnt(t) + xappConn2.TestMsgCnt(t) + e2termConn.TestMsgCnt(t) + mainCtrl.wait_registry_empty(t, 15) } diff --git a/pkg/control/ut_stub_rtmgr_test.go b/pkg/control/ut_stub_rtmgr_test.go index bdca293..59467dc 100644 --- a/pkg/control/ut_stub_rtmgr_test.go +++ b/pkg/control/ut_stub_rtmgr_test.go @@ -84,12 +84,22 @@ func (hc *testingHttpRtmgrStub) http_handler(w http.ResponseWriter, r *http.Requ hc.Lock() defer hc.Unlock() - var req rtmgr_models.XappSubscriptionData - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - xapp.Logger.Error("%s", err.Error()) + if r.Method == http.MethodPost || r.Method == http.MethodDelete { + var req rtmgr_models.XappSubscriptionData + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + xapp.Logger.Error("%s", err.Error()) + } + xapp.Logger.Info("(%s) handling SubscriptionID=%d Address=%s Port=%d", hc.desc, *req.SubscriptionID, *req.Address, *req.Port) + } + if r.Method == http.MethodPut { + var req rtmgr_models.XappList + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + xapp.Logger.Error("%s", err.Error()) + } + xapp.Logger.Info("(%s) handling put", hc.desc) } - xapp.Logger.Info("(%s) handling Address=%s Port=%d SubscriptionID=%d", hc.desc, *req.Address, *req.Port, *req.SubscriptionID) var code int = 0 switch r.Method { @@ -107,6 +117,13 @@ func (hc *testingHttpRtmgrStub) http_handler(w http.ResponseWriter, r *http.Requ code = 400 } } + case http.MethodPut: + code = 201 + if hc.eventWaiter != nil { + if hc.eventWaiter.nextActionOk == false { + code = 400 + } + } default: code = 200 } diff --git a/pkg/control/ut_stub_xapp_test.go b/pkg/control/ut_stub_xapp_test.go index a524d9b..331d14d 100644 --- a/pkg/control/ut_stub_xapp_test.go +++ b/pkg/control/ut_stub_xapp_test.go @@ -111,7 +111,42 @@ func (tc *testingXappStub) Consume(params *xapp.RMRParams) (err error) { //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -func (xappConn *testingXappStub) handle_xapp_subs_req(t *testing.T, oldTrans *xappTransaction) *xappTransaction { +type test_subs_req_params struct { + req *e2ap.E2APSubscriptionRequest +} + +func (p *test_subs_req_params) Init() { + p.req = &e2ap.E2APSubscriptionRequest{} + + p.req.RequestId.Id = 1 + p.req.RequestId.Seq = 0 + p.req.FunctionId = 1 + + p.req.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true + p.req.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150") + p.req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 123 + p.req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDHomeBits28 + + // gnb -> enb outgoing + // enb -> gnb incoming + // X2 36423-f40.doc + p.req.EventTriggerDefinition.InterfaceDirection = e2ap.E2AP_InterfaceDirectionIncoming + p.req.EventTriggerDefinition.ProcedureCode = 5 //28 35 + p.req.EventTriggerDefinition.TypeOfMessage = e2ap.E2AP_InitiatingMessage + + p.req.ActionSetups = make([]e2ap.ActionToBeSetupItem, 1) + p.req.ActionSetups[0].ActionId = 0 + p.req.ActionSetups[0].ActionType = e2ap.E2AP_ActionTypeReport + p.req.ActionSetups[0].ActionDefinition.Present = false + //p.req.ActionSetups[index].ActionDefinition.StyleId = 255 + //p.req.ActionSetups[index].ActionDefinition.ParamId = 222 + p.req.ActionSetups[0].SubsequentAction.Present = true + p.req.ActionSetups[0].SubsequentAction.Type = e2ap.E2AP_SubSeqActionTypeContinue + p.req.ActionSetups[0].SubsequentAction.TimetoWait = e2ap.E2AP_TimeToWaitZero + +} + +func (xappConn *testingXappStub) handle_xapp_subs_req(t *testing.T, rparams *test_subs_req_params, oldTrans *xappTransaction) *xappTransaction { xapp.Logger.Info("(%s) handle_xapp_subs_req", xappConn.desc) e2SubsReq := xapp_e2asnpacker.NewPackerSubscriptionRequest() @@ -120,35 +155,14 @@ func (xappConn *testingXappStub) handle_xapp_subs_req(t *testing.T, oldTrans *xa //--------------------------------- xapp.Logger.Info("(%s) Send Subs Req", xappConn.desc) - req := &e2ap.E2APSubscriptionRequest{} + myparams := rparams - req.RequestId.Id = 1 - req.RequestId.Seq = 0 - req.FunctionId = 1 - - req.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true - req.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150") - req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 123 - req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDHomeBits28 + if myparams == nil { + myparams = &test_subs_req_params{} + myparams.Init() + } - // gnb -> enb outgoing - // enb -> gnb incoming - // X2 36423-f40.doc - req.EventTriggerDefinition.InterfaceDirection = e2ap.E2AP_InterfaceDirectionIncoming - req.EventTriggerDefinition.ProcedureCode = 5 //28 35 - req.EventTriggerDefinition.TypeOfMessage = e2ap.E2AP_InitiatingMessage - - req.ActionSetups = make([]e2ap.ActionToBeSetupItem, 1) - req.ActionSetups[0].ActionId = 0 - req.ActionSetups[0].ActionType = e2ap.E2AP_ActionTypeReport - req.ActionSetups[0].ActionDefinition.Present = false - //req.ActionSetups[index].ActionDefinition.StyleId = 255 - //req.ActionSetups[index].ActionDefinition.ParamId = 222 - req.ActionSetups[0].SubsequentAction.Present = true - req.ActionSetups[0].SubsequentAction.Type = e2ap.E2AP_SubSeqActionTypeContinue - req.ActionSetups[0].SubsequentAction.TimetoWait = e2ap.E2AP_TimeToWaitZero - - e2SubsReq.Set(req) + e2SubsReq.Set(myparams.req) xapp.Logger.Debug("%s", e2SubsReq.String()) err, packedMsg := e2SubsReq.Pack(nil) if err != nil { @@ -327,7 +341,7 @@ func (xappConn *testingXappStub) handle_xapp_subs_del_resp(t *testing.T, trans * if msg.Mtype != xapp.RICMessageTypes["RIC_SUB_DEL_RESP"] { testError(t, "(%s) Received RIC_SUB_DEL_RESP wrong mtype expected %s got %s, error", xappConn.desc, "RIC_SUB_DEL_RESP", xapp.RicMessageTypeToName[msg.Mtype]) return - } else if msg.Xid != trans.xid { + } else if trans != nil && msg.Xid != trans.xid { testError(t, "(%s) Received RIC_SUB_DEL_RESP wrong xid expected %s got %s, error", xappConn.desc, trans.xid, msg.Xid) return } else { -- 2.16.6