From 814531997bde6e8c8722a6834e81faaf3c0fbb7d Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 5 Jun 2016 15:49:36 +0200 Subject: [PATCH] SMG - Fix session timeouts in case of session relocation --- apier/v1/accounts.go | 23 +------ console/balance_set.go | 5 +- sessionmanager/smg_it_test.go | 116 ++++++++++++++++++++++++++++++++++ sessionmanager/smgeneric.go | 3 +- utils/apitpdata.go | 19 ++++++ 5 files changed, 141 insertions(+), 25 deletions(-) diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index 620b64c48..0085dec86 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -458,26 +458,7 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st return nil } -type AttrSetBalance struct { - Tenant string - Account string - BalanceType string - BalanceUUID *string - BalanceID *string - Directions *string - Value *float64 - ExpiryTime *string - RatingSubject *string - Categories *string - DestinationIds *string - TimingIds *string - Weight *float64 - SharedGroups *string - Blocker *bool - Disabled *bool -} - -func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { +func (self *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } @@ -548,7 +529,7 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { return nil } -func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error { +func (self *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } diff --git a/console/balance_set.go b/console/balance_set.go index bc52e8489..0cbd862e7 100644 --- a/console/balance_set.go +++ b/console/balance_set.go @@ -19,7 +19,6 @@ along with this program. If not, see package console import ( - "github.com/cgrates/cgrates/apier/v1" "github.com/cgrates/cgrates/utils" ) @@ -36,7 +35,7 @@ func init() { type CmdSetBalance struct { name string rpcMethod string - rpcParams *v1.AttrSetBalance + rpcParams *utils.AttrSetBalance *CommandExecuter } @@ -50,7 +49,7 @@ func (self *CmdSetBalance) RpcMethod() string { func (self *CmdSetBalance) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { - self.rpcParams = &v1.AttrSetBalance{BalanceType: utils.MONETARY} + self.rpcParams = &utils.AttrSetBalance{BalanceType: utils.MONETARY} } return self.rpcParams } diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index 1ae469fbf..bf6025dae 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -708,3 +708,119 @@ func TestSMGVoiceSessionTTL(t *testing.T) { } } } + +func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { + if !*testIntegration { + return + } + attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestTTLWithRelocate", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestTTLWithRelocate"), + Value: utils.Float64Pointer(300), RatingSubject: utils.StringPointer("*zero50ms")} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + var acnt *engine.Account + attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} + eAcntVal := 300.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + smgEv := SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT_SESSION_TTL_RELOCATE", + utils.TOR: utils.VOICE, + utils.ACCID: "12361", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "TestTTLWithRelocate", + utils.SUBJECT: "TestTTLWithRelocate", + utils.DESTINATION: "1009", + utils.CATEGORY: "call", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:49", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "2m", + } + var maxUsage float64 + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 120 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 180.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + var aSessions []*ActiveSession + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != time.Duration(120)*time.Second { + t.Errorf("Expecting 2m, received usage: %v", aSessions[0].Usage) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: smgEv[utils.EVENT_NAME], + utils.TOR: smgEv[utils.TOR], + utils.InitialOriginID: smgEv[utils.ACCID], + utils.ACCID: "12362", + utils.DIRECTION: smgEv[utils.DIRECTION], + utils.ACCOUNT: smgEv[utils.ACCOUNT], + utils.SUBJECT: smgEv[utils.SUBJECT], + utils.DESTINATION: smgEv[utils.DESTINATION], + utils.CATEGORY: smgEv[utils.CATEGORY], + utils.TENANT: smgEv[utils.TENANT], + utils.REQTYPE: smgEv[utils.REQTYPE], + utils.USAGE: "2m", + utils.LastUsed: "30s", + } + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 120 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 150.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != time.Duration(150)*time.Second { + t.Errorf("Expecting 2m30s, received usage: %v", aSessions[0].Usage) + } + time.Sleep(100 * time.Millisecond) + eAcntVal = 149.95 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 0 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if cdrs[0].Usage != "150.05" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } + +} diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 005750af1..de1135168 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -246,6 +246,7 @@ func (self *SMGeneric) sessionRelocate(sessionID, initialID string) error { return nil, utils.ErrNotFound } for i, s := range ss { + s.eventStart[utils.ACCID] = sessionID // Overwrite initialSessionID with new one self.indexSession(sessionID, s) if i == 0 { self.unindexSession(initialID) @@ -301,7 +302,6 @@ func (self *SMGeneric) InitiateSession(gev SMGenericEvent, clnt *rpc2.Client) (t // Execute debits for usage/maxUsage func (self *SMGeneric) UpdateSession(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { - self.resetTerminatorTimer(gev.GetUUID(), gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) if initialID, err := gev.GetFieldAsString(utils.InitialOriginID); err == nil { err := self.sessionRelocate(gev.GetUUID(), initialID) if err == utils.ErrNotFound { // Session was already relocated, create a new session with this update @@ -311,6 +311,7 @@ func (self *SMGeneric) UpdateSession(gev SMGenericEvent, clnt *rpc2.Client) (tim return nilDuration, err } } + self.resetTerminatorTimer(gev.GetUUID(), gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) var lastUsed *time.Duration evLastUsed, err := gev.GetLastUsed(utils.META_DEFAULT) if err != nil && err != utils.ErrNotFound { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 18bbf5c23..ed9cee7f6 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1178,3 +1178,22 @@ type AttrRateCDRs struct { SendToStatS *bool // Set to true if the CDRs should be sent to stats server ReplicateCDRs *bool // Replicate results } + +type AttrSetBalance struct { + Tenant string + Account string + BalanceType string + BalanceUUID *string + BalanceID *string + Directions *string + Value *float64 + ExpiryTime *string + RatingSubject *string + Categories *string + DestinationIds *string + TimingIds *string + Weight *float64 + SharedGroups *string + Blocker *bool + Disabled *bool +}