tests passing on get max session time

This commit is contained in:
Radu Ioan Fericean
2013-10-04 16:18:28 +03:00
parent c889eafb20
commit 7632a8f14e
11 changed files with 72 additions and 64 deletions

View File

@@ -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,
}

View File

@@ -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
}
/*

View File

@@ -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()
}

View File

@@ -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())
}
}

View File

@@ -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},
}},
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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++
}
}

View File

@@ -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 {