From 7632a8f14ec503c985fe367ca12d10242ff345cc Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Fri, 4 Oct 2013 16:18:28 +0300 Subject: [PATCH] tests passing on get max session time --- apier/v1/tpactions.go | 10 ++++---- engine/balances.go | 18 ++++++++++---- engine/callcost.go | 2 +- engine/callcost_test.go | 8 +++---- engine/calldesc_test.go | 2 +- engine/storage_sql.go | 8 +++---- engine/userbalance.go | 38 +++++++++--------------------- engine/userbalance_test.go | 26 ++++++++++++++++---- sessionmanager/fssessionmanager.go | 2 +- sessionmanager/session.go | 2 +- utils/apitpdata.go | 20 ++++++++-------- 11 files changed, 72 insertions(+), 64 deletions(-) diff --git a/apier/v1/tpactions.go b/apier/v1/tpactions.go index b2cde95c2..15ee69612 100644 --- a/apier/v1/tpactions.go +++ b/apier/v1/tpactions.go @@ -51,12 +51,12 @@ func (self *ApierV1) SetTPActions(attrs utils.TPActions, reply *string) error { BalanceId: act.BalanceType, Direction: act.Direction, ExpirationString: act.ExpiryTime, + ExtraParameters: act.ExtraParameters, Balance: &engine.Balance{ - Value: act.Units, - DestinationId: act.DestinationId, - SpecialPriceType: act.RateType, - SpecialPrice: act.Rate, - Weight: act.MinutesWeight, + Value: act.Units, + DestinationId: act.DestinationId, + RateSubject: act.RateSubject, + Weight: act.BalanceWeight, }, Weight: act.Weight, } diff --git a/engine/balances.go b/engine/balances.go index d138ff6c1..88658ad00 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -64,22 +64,30 @@ func (b *Balance) Clone() *Balance { // Returns the available number of seconds for a specified credit func (b *Balance) GetSecondsForCredit(cd *CallDescriptor, credit float64) (seconds float64) { seconds = b.Value - // TODO: fix this cc, err := b.GetCost(cd) if err != nil { Logger.Err(fmt.Sprintf("Error getting new cost for balance subject: %v", err)) return 0 } if cc.Cost > 0 { - seconds = math.Min(credit/cc.Cost, b.Value) + secondCost := cc.Cost / cc.GetDuration().Seconds() + // TODO: this is not very accurate + // we should iterate timespans and increment to get exact number of minutes for + // available credit + seconds = math.Min(credit/secondCost, b.Value) } return } func (b *Balance) GetCost(cd *CallDescriptor) (*CallCost, error) { - cd.Subject = b.RateSubject - cd.Account = cd.Subject - return cd.GetCost() + if b.RateSubject != "" { + cd.Subject = b.RateSubject + cd.Account = cd.Subject + return cd.GetCost() + } + cc := cd.CreateCallCost() + cc.Cost = 0 + return cc, nil } /* diff --git a/engine/callcost.go b/engine/callcost.go index 778b54e53..3ac52e29a 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -67,7 +67,7 @@ func (cc *CallCost) GetStartTime() time.Time { return cc.Timespans[0].TimeStart } -func (cc *CallCost) GetTotalDuration() (td time.Duration) { +func (cc *CallCost) GetDuration() (td time.Duration) { for _, ts := range cc.Timespans { td += ts.GetDuration() } diff --git a/engine/callcost_test.go b/engine/callcost_test.go index 0c2d49328..afd85e8b6 100644 --- a/engine/callcost_test.go +++ b/engine/callcost_test.go @@ -128,8 +128,8 @@ func TestMultipleInputRightMerge(t *testing.T) { func TestCallCostGetDurationZero(t *testing.T) { cc := &CallCost{} - if cc.GetTotalDuration().Seconds() != 0 { - t.Error("Wrong call cost duration for zero timespans: ", cc.GetTotalDuration()) + if cc.GetDuration().Seconds() != 0 { + t.Error("Wrong call cost duration for zero timespans: ", cc.GetDuration()) } } @@ -146,7 +146,7 @@ func TestCallCostGetDuration(t *testing.T) { }, }, } - if cc.GetTotalDuration().Seconds() != 90 { - t.Error("Wrong call cost duration: ", cc.GetTotalDuration()) + if cc.GetDuration().Seconds() != 90 { + t.Error("Wrong call cost duration: ", cc.GetDuration()) } } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 0fd7c02ed..5823f5e7e 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -50,7 +50,7 @@ func populateDB() { Type: UB_TYPE_PREPAID, BalanceMap: map[string]BalanceChain{ MINUTES + OUTBOUND: BalanceChain{ - &Balance{Value: 20, DestinationId: "NAT", Weight: 10}, + &Balance{Value: 20, DestinationId: "NAT", Weight: 10, RateSubject: "rif"}, &Balance{Value: 100, DestinationId: "RET", Weight: 20}, }}, } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index c8cc00c5b..eed027380 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -561,12 +561,12 @@ func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, err i := 0 for rows.Next() { i++ //Keep here a reference so we know we got at least one result - var action, balanceId, dir, destId, rateType, expTime string - var units, rate, minutesWeight, weight float64 - if err = rows.Scan(&action, &balanceId, &dir, &units, &expTime, &destId, &rateType, &rate, &minutesWeight, &weight); err != nil { + var action, balanceId, dir, destId, rateSubject, expTime, extraParameters string + var units, balanceWeight, weight float64 + if err = rows.Scan(&action, &balanceId, &dir, &units, &expTime, &destId, &rateSubject, &balanceWeight, &extraParameters, &weight); err != nil { return nil, err } - acts.Actions = append(acts.Actions, utils.Action{action, balanceId, dir, units, expTime, destId, rateType, rate, minutesWeight, weight}) + acts.Actions = append(acts.Actions, utils.Action{action, balanceId, dir, units, expTime, destId, rateSubject, balanceWeight, extraParameters, weight}) } if i == 0 { return nil, nil diff --git a/engine/userbalance.go b/engine/userbalance.go index 0972455cf..e8e0f0ac5 100644 --- a/engine/userbalance.go +++ b/engine/userbalance.go @@ -65,35 +65,15 @@ type UserBalance struct { BalanceMap map[string]BalanceChain UnitCounters []*UnitsCounter ActionTriggers ActionTriggerPriotityList - - Groups GroupLinks // user info about groups + Groups GroupLinks // user info about groups // group information UserIds []string // group info about users } // Returns user's available minutes for the specified destination func (ub *UserBalance) getSecondsForPrefix(cd *CallDescriptor) (seconds, credit float64, balances BalanceChain) { - credit = ub.getBalanceForPrefix(cd.Destination, ub.BalanceMap[CREDIT+cd.Direction]).GetTotalValue() - if len(ub.BalanceMap[MINUTES+cd.Direction]) == 0 { - // Logger.Debug("There are no minute buckets to check for user: ", ub.Id) - return - } - for _, b := range ub.BalanceMap[MINUTES+cd.Direction] { - if b.IsExpired() { - continue - } - precision, err := storageGetter.DestinationContainsPrefix(b.DestinationId, cd.Destination) - if err != nil { - continue - } - if precision > 0 { - b.precision = precision - if b.Value > 0 { - balances = append(balances, b) - } - } - } - balances.Sort() // sorts the buckets according to priority, precision or price + credit = ub.getBalancesForPrefix(cd.Destination, ub.BalanceMap[CREDIT+cd.Direction]).GetTotalValue() + balances = ub.getBalancesForPrefix(cd.Destination, ub.BalanceMap[MINUTES+cd.Direction]) for _, b := range balances { s := b.GetSecondsForCredit(cd, credit) cc, err := b.GetCost(cd) @@ -101,7 +81,11 @@ func (ub *UserBalance) getSecondsForPrefix(cd *CallDescriptor) (seconds, credit Logger.Err(fmt.Sprintf("Error getting new cost for balance subject: %v", err)) continue } - credit -= s * cc.Cost + if cc.Cost > 0 && cc.GetDuration() > 0 { + // TODO: fix this + secondCost := cc.Cost / cc.GetDuration().Seconds() + credit -= s * secondCost + } seconds += s } return @@ -140,7 +124,7 @@ func (ub *UserBalance) debitBalanceAction(a *Action) error { return nil //ub.BalanceMap[id].GetTotalValue() } -func (ub *UserBalance) getBalanceForPrefix(prefix string, balances BalanceChain) BalanceChain { +func (ub *UserBalance) getBalancesForPrefix(prefix string, balances BalanceChain) BalanceChain { var usefulBalances BalanceChain for _, b := range balances { if b.IsExpired() || (ub.Type != UB_TYPE_POSTPAID && b.Value <= 0) { @@ -170,8 +154,8 @@ This method is the core of userbalance debiting: don't panic just follow the bra func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error { minuteBalances := ub.BalanceMap[MINUTES+cc.Direction] moneyBalances := ub.BalanceMap[CREDIT+cc.Direction] - usefulMinuteBalances := ub.getBalanceForPrefix(cc.Destination, minuteBalances) - usefulMoneyBalances := ub.getBalanceForPrefix(cc.Destination, moneyBalances) + usefulMinuteBalances := ub.getBalancesForPrefix(cc.Destination, minuteBalances) + usefulMoneyBalances := ub.getBalancesForPrefix(cc.Destination, moneyBalances) // debit connect fee if cc.ConnectFee > 0 { amount := cc.ConnectFee diff --git a/engine/userbalance_test.go b/engine/userbalance_test.go index ca601022d..b41816160 100644 --- a/engine/userbalance_test.go +++ b/engine/userbalance_test.go @@ -112,26 +112,42 @@ func TestGetSecondsForPrefix(t *testing.T) { b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} ub1 := &UserBalance{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 200}}}} cd := &CallDescriptor{ - Destination: "0723", + TOR: "0", + Tenant: "vdf", + TimeStart: time.Date(2013, 10, 4, 15, 46, 0, 0, time.UTC), + TimeEnd: time.Date(2013, 10, 4, 15, 46, 10, 0, time.UTC), + LoopIndex: 0, + CallDuration: 10 * time.Second, + Direction: OUTBOUND, + Destination: "0723", } seconds, credit, bucketList := ub1.getSecondsForPrefix(cd) expected := 110.0 if credit != 200 || seconds != expected || bucketList[0].Weight < bucketList[1].Weight { + t.Log(seconds, credit, bucketList) t.Errorf("Expected %v was %v", expected, seconds) } } func TestGetSpecialPricedSeconds(t *testing.T) { - b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"} - b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"} + b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: "minu"} + b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET", RateSubject: "minu"} ub1 := &UserBalance{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}} cd := &CallDescriptor{ - Destination: "0723", + TOR: "0", + Tenant: "vdf", + TimeStart: time.Date(2013, 10, 4, 15, 46, 0, 0, time.UTC), + TimeEnd: time.Date(2013, 10, 4, 15, 46, 10, 0, time.UTC), + LoopIndex: 0, + CallDuration: 10 * time.Second, + Direction: OUTBOUND, + Destination: "0723", } seconds, credit, bucketList := ub1.getSecondsForPrefix(cd) expected := 21.0 if credit != 0 || seconds != expected || len(bucketList) < 2 || bucketList[0].Weight < bucketList[1].Weight { + t.Log(seconds, credit, bucketList) t.Errorf("Expected %v was %v", expected, seconds) } } @@ -510,7 +526,7 @@ func TestDebitCreditNoConectFeeCredit(t *testing.T) { t.Error("Error debiting balance: ", err) } - if len(cc.Timespans) != 0 || cc.GetTotalDuration() != 0 { + if len(cc.Timespans) != 0 || cc.GetDuration() != 0 { t.Error("Error cutting at no connect fee: ", cc.Timespans) } } diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index 283826422..987aaf72f 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -307,7 +307,7 @@ func (sm *FSSessionManager) LoopAction(s *Session, cd *engine.CallDescriptor, in s.sessionManager.DisconnectSession(s, SYSTEM_ERROR) } engine.Logger.Debug(fmt.Sprintf("Result of MaxDebit call: %v", cc)) - if cc.GetTotalDuration() == 0 || err != nil { + if cc.GetDuration() == 0 || err != nil { engine.Logger.Info(fmt.Sprintf("No credit left: Disconnect %v", s)) sm.DisconnectSession(s, INSUFFICIENT_FUNDS) return diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 3e5cadb20..c527ebc63 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -87,7 +87,7 @@ func (s *Session) startDebitLoop() { } nextCd.TimeEnd = nextCd.TimeStart.Add(s.sessionManager.GetDebitPeriod()) cc := s.sessionManager.LoopAction(s, &nextCd, index) - time.Sleep(cc.GetTotalDuration()) + time.Sleep(cc.GetDuration()) index++ } } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index fcd020c46..37fe35ac9 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -91,16 +91,16 @@ type TPActions struct { } type Action struct { - Identifier string // Identifier mapped in the code - BalanceType string // Type of balance the action will operate on - Direction string // Balance direction - Units float64 // Number of units to add/deduct - ExpiryTime string // Time when the units will expire - DestinationId string // Destination profile id - RateType string // Type of rate <*absolute|*percent> - Rate float64 // Price value - MinutesWeight float64 // Minutes weight - Weight float64 // Action's weight + Identifier string // Identifier mapped in the code + BalanceType string // Type of balance the action will operate on + Direction string // Balance direction + Units float64 // Number of units to add/deduct + ExpiryTime string // Time when the units will expire + DestinationId string // Destination profile id + RateSubject string // Type of rate <*absolute|*percent> + BalanceWeight float64 // Balance weight + ExtraParameters string + Weight float64 // Action's weight } type ApiTPActionTimings struct {