diff --git a/packages/debian/changelog b/packages/debian/changelog index 9acf0b999..e5edd2622 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -7,6 +7,7 @@ cgrates (0.10.2~dev) UNRELEASED; urgency=medium * [ERs] Renamed *default reader folders * [General] Added *mo+extraDuration time support (e.g. *mo+1h will be time.Now() + 1 month + 1 hour) + * [SessionS] Use correctly SessionTTLUsage when calculate end usage in case of terminate session from ttl mechanism -- DanB Tue, 12 May 2020 13:08:15 +0300 diff --git a/sessions/sessions.go b/sessions/sessions.go index d04c268d3..aad8502ea 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -283,12 +283,8 @@ func (sS *SessionS) setSTerminator(s *Session) { go func() { select { case <-s.sTerminator.timer.C: - endUsage := s.sTerminator.ttl - if s.sTerminator.ttlUsage != nil { - endUsage = *s.sTerminator.ttlUsage - } - sS.forceSTerminate(s, endUsage, - s.sTerminator.ttlLastUsed) + sS.forceSTerminate(s, s.sTerminator.ttl, + s.sTerminator.ttlUsage, s.sTerminator.ttlLastUsed) case <-s.sTerminator.endChan: s.sTerminator.timer.Stop() } @@ -298,10 +294,10 @@ func (sS *SessionS) setSTerminator(s *Session) { // forceSTerminate is called when a session times-out or it is forced from CGRateS side // not thread safe -func (sS *SessionS) forceSTerminate(s *Session, extraDebit time.Duration, lastUsed *time.Duration) (err error) { - if extraDebit != 0 { +func (sS *SessionS) forceSTerminate(s *Session, extraUsage time.Duration, tUsage, lastUsed *time.Duration) (err error) { + if extraUsage != 0 { for i := range s.SRuns { - if _, err = sS.debitSession(s, i, extraDebit, lastUsed); err != nil { + if _, err = sS.debitSession(s, i, extraUsage, lastUsed); err != nil { utils.Logger.Warning( fmt.Sprintf( "<%s> failed debitting cgrID %s, sRunIdx: %d, err: %s", @@ -310,7 +306,7 @@ func (sS *SessionS) forceSTerminate(s *Session, extraDebit time.Duration, lastUs } } // we apply the correction before - if err = sS.endSession(s, nil, nil, nil, false); err != nil { + if err = sS.endSession(s, tUsage, lastUsed, nil, false); err != nil { utils.Logger.Warning( fmt.Sprintf( "<%s> failed force terminating session with ID <%s>, err: <%s>", @@ -477,7 +473,7 @@ func (sS *SessionS) debitLoopSession(s *Session, sRunIdx int, fmt.Sprintf("<%s> could not disconnect session: %s, error: %s", utils.SessionS, s.cgrID(), err.Error())) } - if err = sS.forceSTerminate(s, 0, nil); err != nil { + if err = sS.forceSTerminate(s, 0, nil, nil); err != nil { utils.Logger.Warning(fmt.Sprintf("<%s> failed force-terminating session: <%s>, err: <%s>", utils.SessionS, s.cgrID(), err)) } s.Unlock() @@ -503,7 +499,7 @@ func (sS *SessionS) debitLoopSession(s *Session, sRunIdx int, utils.Logger.Warning( fmt.Sprintf("<%s> could not disconnect session: <%s>, error: <%s>", utils.SessionS, s.cgrID(), err.Error())) - if err = sS.forceSTerminate(s, 0, nil); err != nil { + if err = sS.forceSTerminate(s, 0, nil, nil); err != nil { utils.Logger.Warning(fmt.Sprintf("<%s> failed force-terminating session: <%s>, err: <%s>", utils.SessionS, s.cgrID(), err)) } @@ -1228,7 +1224,7 @@ func (sS *SessionS) syncSessions() { if len(ss) == 0 { continue } - if err := sS.forceSTerminate(ss[0], 0, nil); err != nil { + if err := sS.forceSTerminate(ss[0], 0, nil, nil); err != nil { utils.Logger.Warning( fmt.Sprintf("<%s> failed force-terminating session: <%s>, err: <%s>", utils.SessionS, cgrID, err.Error())) @@ -3251,7 +3247,7 @@ func (sS *SessionS) BiRPCv1ForceDisconnect(clnt rpcclient.ClientConnector, if len(ss) == 0 { continue } - if errTerm := sS.forceSTerminate(ss[0], 0, nil); errTerm != nil { + if errTerm := sS.forceSTerminate(ss[0], 0, nil, nil); errTerm != nil { utils.Logger.Warning( fmt.Sprintf( "<%s> failed force-terminating session with id: <%s>, err: <%s>", diff --git a/sessions/sessions_data_it_test.go b/sessions/sessions_data_it_test.go index c5e0dc243..394a1eff1 100644 --- a/sessions/sessions_data_it_test.go +++ b/sessions/sessions_data_it_test.go @@ -609,12 +609,25 @@ func testSessionsDataTTLExpired(t *testing.T) { } time.Sleep(70 * time.Millisecond) - eAcntVal = 99328.000000 + eAcntVal = 100352.000000 if err := sDataRPC.Call(utils.APIerSv2GetAccount, acntAttrs, &acnt); err != nil { t.Error(err) } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } + + // verify the cdr usage SessionTTLUsage ( 2048) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{acntAttrs.Account}} + if err := sDataRPC.Call(utils.APIerSv2GetCDRs, &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 != "2048" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } } func testSessionsDataTTLExpMultiUpdates(t *testing.T) { @@ -734,7 +747,7 @@ func testSessionsDataTTLExpMultiUpdates(t *testing.T) { } time.Sleep(60 * time.Millisecond) // TTL will kick in - eAcntVal = 98304.000000 // 1MB is returned + eAcntVal = 100352.000000 // initial balance ( 102400 ) - SessionTTLUsage from update ( 2048 ) if err := sDataRPC.Call(utils.APIerSv2GetAccount, acntAttrs, &acnt); err != nil { t.Error(err) } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { @@ -744,6 +757,19 @@ func testSessionsDataTTLExpMultiUpdates(t *testing.T) { new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } + + // verify the cdr usage SessionTTLUsage ( 2048) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{acntAttrs.Account}} + if err := sDataRPC.Call(utils.APIerSv2GetCDRs, &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 != "2048" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } } func testSessionsDataMultipleDataNoUsage(t *testing.T) {