more tests

This commit is contained in:
Radu Ioan Fericean
2013-10-07 17:02:45 +03:00
parent 036e363ca8
commit 617c3f9591
8 changed files with 182 additions and 53 deletions

View File

@@ -47,7 +47,7 @@ func (cc *CallCost) Merge(other *CallCost) {
}
ts := cc.Timespans[len(cc.Timespans)-1]
otherTs := other.Timespans[0]
if reflect.DeepEqual(ts.RatingPlan, otherTs.RatingPlan) &&
if reflect.DeepEqual(ts.ratingPlan, otherTs.ratingPlan) &&
reflect.DeepEqual(ts.RateInterval, otherTs.RateInterval) {
// extend the last timespan with
ts.TimeEnd = ts.TimeEnd.Add(otherTs.GetDuration())

View File

@@ -201,17 +201,16 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti
if len(cd.RatingPlans) == 0 {
return
}
firstSpan.RatingPlan = cd.RatingPlans[0]
firstSpan.ratingPlan = cd.RatingPlans[0]
// split on activation periods
afterStart, afterEnd := false, false //optimization for multiple activation periods
for _, ap := range cd.RatingPlans {
if !afterStart && !afterEnd && ap.ActivationTime.Before(cd.TimeStart) {
firstSpan.RatingPlan = ap
for _, rp := range cd.RatingPlans {
if !afterStart && !afterEnd && rp.ActivationTime.Before(cd.TimeStart) {
firstSpan.ratingPlan = rp
} else {
afterStart = true
for i := 0; i < len(timespans); i++ {
newTs := timespans[i].SplitByRatingPlan(ap)
newTs := timespans[i].SplitByRatingPlan(rp)
if newTs != nil {
timespans = append(timespans, newTs)
} else {
@@ -223,16 +222,16 @@ func (cd *CallDescriptor) splitInTimeSpans(firstSpan *TimeSpan) (timespans []*Ti
}
// split on price intervals
for i := 0; i < len(timespans); i++ {
ap := timespans[i].RatingPlan
rp := timespans[i].ratingPlan
//timespans[i].RatingPlan = nil
ap.RateIntervals.Sort()
for _, interval := range ap.RateIntervals {
rp.RateIntervals.Sort()
for _, interval := range rp.RateIntervals {
if timespans[i].RateInterval != nil && timespans[i].RateInterval.Weight < interval.Weight {
continue // if the timespan has an interval than it already has a heigher weight
}
newTs := timespans[i].SplitByRateInterval(interval)
if newTs != nil {
newTs.RatingPlan = ap
newTs.ratingPlan = rp
timespans = append(timespans, newTs)
}
}

View File

@@ -76,6 +76,27 @@ func TestSplitSpans(t *testing.T) {
}
}
func TestSplitSpansRoundToIncrements(t *testing.T) {
t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC)
t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC)
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second}
cd.LoadRatingPlans()
timespans := cd.splitInTimeSpans(nil)
if len(timespans) != 2 {
t.Log(cd.RatingPlans)
t.Error("Wrong number of timespans: ", len(timespans))
}
var d time.Duration
for _, ts := range timespans {
d += ts.GetDuration()
t.Log(ts.GetDuration())
}
if d != 132*time.Second {
t.Error("Wrong duration for timespans: ", d)
}
}
func TestGetCost(t *testing.T) {
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
@@ -87,6 +108,20 @@ func TestGetCost(t *testing.T) {
}
}
func TestGetCostRateGroups(t *testing.T) {
t1 := time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC)
t2 := time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC)
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "test", Subject: "trp", Destination: "0256", TimeStart: t1, TimeEnd: t2, CallDuration: 132 * time.Second}
result, err := cd.GetCost()
if err != nil {
t.Error("Error getting cost: ", err)
}
if result.Cost != 132 {
t.Error("Error calculating cost: ", result.Timespans[0])
}
}
func TestGetCostNoConnectFee(t *testing.T) {
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)

View File

@@ -52,6 +52,8 @@ R2,0,0.1,60s,1s,0,*middle,2,10
R3,0,0.05,60s,1s,0,*middle,2,10
R4,1,1,1s,1s,0,*up,2,10
R5,0,0.5,1s,1s,0,*down,2,10
LANDLINE_OFFPEAK,0,1,1s,60s,0s,*up,4,10
LANDLINE_OFFPEAK,0,1,1s,1s,60s,*up,4,10
`
destinationRates = `
RT_STANDARD,GERMANY,R1
@@ -62,6 +64,7 @@ RT_STD_WEEKEND,GERMANY,R2
RT_STD_WEEKEND,GERMANY_O2,R3
P1,NAT,R4
P2,NAT,R5
T1,NAT,LANDLINE_OFFPEAK
`
destinationRateTimings = `
STANDARD,RT_STANDARD,WORKDAYS_00,10
@@ -72,6 +75,7 @@ DEFAULT,RT_DEFAULT,WORKDAYS_00,10
EVENING,P1,WORKDAYS_00,10
EVENING,P2,WORKDAYS_18,10
EVENING,P2,WEEKENDS,10
TDRT,T1,WORKDAYS_00,10
`
ratingProfiles = `
CUSTOMER_1,0,*out,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb
@@ -85,6 +89,7 @@ vdf,0,*out,*any,2012-02-28T00:00:00Z,EVENING,
vdf,0,*out,one,2012-02-28T00:00:00Z,STANDARD,
vdf,0,*out,inf,2012-02-28T00:00:00Z,STANDARD,inf
vdf,0,*out,fall,2012-02-28T00:00:00Z,PREMIUM,rif
test,0,*out,trp,2013-10-01T00:00:00Z,TDRT,rif
`
actions = `
MINI,*topup_reset,*monetary,*out,10,*unlimited,,,10,,10
@@ -206,7 +211,7 @@ func TestLoadTimimgs(t *testing.T) {
}
func TestLoadRates(t *testing.T) {
if len(csvr.rates) != 5 {
if len(csvr.rates) != 6 {
t.Error("Failed to load rates: ", csvr.rates)
}
rate := csvr.rates["R1"][0]
@@ -280,10 +285,38 @@ func TestLoadRates(t *testing.T) {
t.Error("Error loading rate: ", csvr.rates)
}
rate = csvr.rates["LANDLINE_OFFPEAK"][0]
if !reflect.DeepEqual(rate, &LoadRate{
Tag: "LANDLINE_OFFPEAK",
ConnectFee: 0,
Price: 1,
RateUnit: time.Second,
RateIncrement: time.Minute,
GroupIntervalStart: 0,
RoundingMethod: utils.ROUNDING_UP,
RoundingDecimals: 4,
Weight: 10,
}) {
t.Errorf("Error loading rate: %+v", rate)
}
rate = csvr.rates["LANDLINE_OFFPEAK"][1]
if !reflect.DeepEqual(rate, &LoadRate{
Tag: "LANDLINE_OFFPEAK",
ConnectFee: 0,
Price: 1,
RateUnit: time.Second,
RateIncrement: time.Second,
GroupIntervalStart: 60 * time.Second,
RoundingMethod: utils.ROUNDING_UP,
RoundingDecimals: 4,
Weight: 10,
}) {
t.Errorf("Error loading rate: %+v", rate)
}
}
func TestLoadDestinationRates(t *testing.T) {
if len(csvr.destinationRates) != 5 {
if len(csvr.destinationRates) != 6 {
t.Error("Failed to load destinationrates: ", csvr.destinationRates)
}
drs := csvr.destinationRates["RT_STANDARD"]
@@ -351,10 +384,20 @@ func TestLoadDestinationRates(t *testing.T) {
}) {
t.Error("Error loading destination rate: ", drs)
}
drs = csvr.destinationRates["T1"]
if !reflect.DeepEqual(drs, []*DestinationRate{
&DestinationRate{
Tag: "T1",
DestinationsTag: "NAT",
rates: csvr.rates["LANDLINE_OFFPEAK"],
},
}) {
t.Error("Error loading destination rate: ", drs)
}
}
func TestLoadDestinationRateTimings(t *testing.T) {
if len(csvr.destinationRateTimings) != 4 {
if len(csvr.destinationRateTimings) != 5 {
t.Error("Failed to load rate timings: ", csvr.destinationRateTimings)
}
rplan := csvr.destinationRateTimings["STANDARD"]
@@ -518,18 +561,67 @@ func TestLoadDestinationRateTimings(t *testing.T) {
},
}
if !reflect.DeepEqual(rplan, expected) {
t.Errorf("Error loading destination rate timing: %#v", rplan)
t.Errorf("Error loading destination rate timing: %+v", rplan)
}
rplan = csvr.destinationRateTimings["TDRT"]
expected = []*DestinationRateTiming{
&DestinationRateTiming{
destinationRates: csvr.destinationRates["T1"],
Weight: 10,
timing: csvr.timings["WORKDAYS_00"],
},
}
if !reflect.DeepEqual(rplan, expected) {
t.Errorf("Error loading destination rate timing: %+v", rplan[0])
}
}
func TestLoadRatingProfiles(t *testing.T) {
if len(csvr.ratingProfiles) != 9 {
if len(csvr.ratingProfiles) != 10 {
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
}
rp := csvr.ratingProfiles["*out:CUSTOMER_1:0:rif:from:tm"]
expected := &RatingProfile{}
if reflect.DeepEqual(rp, expected) {
t.Errorf("Error loading rating profile: %+v", rp.DestinationMap["GERMANY"][1].RateIntervals[2].Rates[0])
rp := csvr.ratingProfiles["*out:test:0:trp"]
expected := &RatingProfile{
Id: "*out:test:0:trp",
FallbackKey: "*out:test:0:rif",
DestinationMap: map[string][]*RatingPlan{
"NAT": []*RatingPlan{
&RatingPlan{
ActivationTime: time.Date(2013, time.October, 1, 0, 0, 0, 0, time.UTC),
RateIntervals: []*RateInterval{
&RateInterval{
Years: Years{},
Months: Months{},
MonthDays: MonthDays{},
WeekDays: WeekDays{1, 2, 3, 4, 5},
StartTime: "00:00:00",
EndTime: "",
Weight: 10,
ConnectFee: 0,
Rates: RateGroups{
&Rate{
GroupIntervalStart: 0,
Value: 1,
RateIncrement: time.Minute,
RateUnit: time.Second,
},
&Rate{
GroupIntervalStart: time.Minute,
Value: 1,
RateIncrement: time.Second,
RateUnit: time.Second,
},
},
RoundingMethod: utils.ROUNDING_UP,
RoundingDecimals: 4,
},
},
},
},
},
}
if !reflect.DeepEqual(rp, expected) {
t.Errorf("Error loading rating profile: %+v")
}
}

View File

@@ -29,7 +29,7 @@ A unit in which a call will be split that has a specific price related interval
type TimeSpan struct {
TimeStart, TimeEnd time.Time
Cost float64
RatingPlan *RatingPlan
ratingPlan *RatingPlan
RateInterval *RateInterval
CallDuration time.Duration // the call duration so far till TimeEnd
overlapped bool // mark a timespan as overlapped by an expanded one
@@ -39,7 +39,7 @@ type TimeSpan struct {
type Increment struct {
Duration time.Duration
Cost float64
BalanceUuid string
BalanceUuids []string // need more than one for minutes with cost
BalanceType string
BalanceRateInterval *RateInterval
MinuteInfo *MinuteInfo
@@ -53,14 +53,16 @@ type MinuteInfo struct {
}
func (incr *Increment) Clone() *Increment {
return &Increment{
nIncr := &Increment{
Duration: incr.Duration,
Cost: incr.Cost,
BalanceUuid: incr.BalanceUuid,
BalanceType: incr.BalanceType,
BalanceRateInterval: incr.BalanceRateInterval,
MinuteInfo: incr.MinuteInfo,
}
nIncr.BalanceUuids = make([]string, len(incr.BalanceUuids))
copy(nIncr.BalanceUuids, incr.BalanceUuids)
return nIncr
}
type Increments []*Increment
@@ -132,7 +134,6 @@ a new timespan starting from the end of the received one.
The interval will attach itself to the timespan that overlaps the interval.
*/
func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
//Logger.Debug("here: ", ts, " +++ ", i)
// if the span is not in interval return nil
if !(i.Contains(ts.TimeStart) || i.Contains(ts.TimeEnd)) {
@@ -141,10 +142,10 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval) (nts *TimeSpan) {
}
// split by GroupStart
i.Rates.Sort()
for _, price := range i.Rates {
if ts.GetGroupStart() < price.GroupIntervalStart && ts.GetGroupEnd() >= price.GroupIntervalStart {
for _, rate := range i.Rates {
if ts.GetGroupStart() < rate.GroupIntervalStart && ts.GetGroupEnd() >= rate.GroupIntervalStart {
ts.SetRateInterval(i)
splitTime := ts.TimeStart.Add(price.GroupIntervalStart - ts.GetGroupStart())
splitTime := ts.TimeStart.Add(rate.GroupIntervalStart - ts.GetGroupStart())
nts = &TimeSpan{TimeStart: splitTime, TimeEnd: ts.TimeEnd}
ts.TimeEnd = splitTime
nts.SetRateInterval(i)
@@ -241,13 +242,13 @@ func (ts *TimeSpan) SplitByDuration(duration time.Duration) *TimeSpan {
}
// Splits the given timespan on activation period's activation time.
func (ts *TimeSpan) SplitByRatingPlan(ap *RatingPlan) (newTs *TimeSpan) {
if !ts.Contains(ap.ActivationTime) {
func (ts *TimeSpan) SplitByRatingPlan(rp *RatingPlan) (newTs *TimeSpan) {
if !ts.Contains(rp.ActivationTime) {
return nil
}
newTs = &TimeSpan{TimeStart: ap.ActivationTime, TimeEnd: ts.TimeEnd, RatingPlan: ap}
newTs = &TimeSpan{TimeStart: rp.ActivationTime, TimeEnd: ts.TimeEnd, ratingPlan: rp}
newTs.CallDuration = ts.CallDuration
ts.TimeEnd = ap.ActivationTime
ts.TimeEnd = rp.ActivationTime
ts.SetNewCallDuration(newTs)
return
}

View File

@@ -193,8 +193,8 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
amount := increment.Duration.Seconds()
if b.Value >= amount {
b.Value -= amount
increment.BalanceUuid = b.Uuid
increment.MinuteInfo = &MinuteInfo{b.DestinationId, amount, 0}
increment.BalanceUuids = append(increment.BalanceUuids, b.Uuid)
increment.MinuteInfo = &MinuteInfo{cc.Destination, amount, 0}
paid = true
if count {
ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
@@ -248,8 +248,8 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
}
cc.Timespans = newTimespans
b.Value -= amount
newTs.Increments[0].BalanceUuid = b.Uuid
newTs.Increments[0].MinuteInfo = &MinuteInfo{b.DestinationId, amount, 0}
newTs.Increments[0].BalanceUuids = append(newTs.Increments[0].BalanceUuids, b.Uuid)
newTs.Increments[0].MinuteInfo = &MinuteInfo{cc.Destination, amount, 0}
paid = true
if count {
ub.countUnits(&Action{BalanceId: MINUTES, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
@@ -274,18 +274,20 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
for nIdx, nInc := range nts.Increments {
// debit minutes and money
seconds := nInc.Duration.Seconds()
amount := nInc.Cost
//cost := nInc.Cost
if b.Value >= seconds {
b.Value -= seconds
nInc.BalanceUuid = b.Uuid
nInc.BalanceUuids = append(nInc.BalanceUuids, b.Uuid)
nInc.MinuteInfo = &MinuteInfo{newCC.Destination, seconds, 0}
if count {
ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: amount, DestinationId: newCC.Destination}})
ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: seconds, DestinationId: newCC.Destination}})
}
} else {
nts.SplitByIncrement(nIdx)
}
}
}
// calculate overlaped timespans
var paidDuration time.Duration
for _, pts := range paidTs {
@@ -349,7 +351,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
amount := increment.Cost
if b.Value >= amount {
b.Value -= amount
increment.BalanceUuid = b.Uuid
increment.BalanceUuids = append(increment.BalanceUuids, b.Uuid)
paid = true
if count {
ub.countUnits(&Action{BalanceId: CREDIT, Direction: cc.Direction, Balance: &Balance{Value: amount, DestinationId: cc.Destination}})
@@ -376,7 +378,7 @@ func (ub *UserBalance) debitCreditBalance(cc *CallCost, count bool) error {
amount := nInc.Cost
if b.Value >= amount {
b.Value -= amount
nInc.BalanceUuid = b.Uuid
nInc.BalanceUuids = append(nInc.BalanceUuids, b.Uuid)
if count {
ub.countUnits(&Action{BalanceId: CREDIT, Direction: newCC.Direction, Balance: &Balance{Value: amount, DestinationId: newCC.Destination}})
}
@@ -446,7 +448,7 @@ func (ub *UserBalance) refoundIncrements(increments Increments, count bool) {
for _, increment := range increments {
var balance *Balance
for _, balanceChain := range ub.BalanceMap {
if balance = balanceChain.GetBalance(increment.BalanceUuid); balance != nil {
if balance = balanceChain.GetBalance(increment.BalanceUuids[0]); balance != nil {
break
}
}

View File

@@ -228,7 +228,7 @@ func TestDebitCreditZeroSecond(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" {
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
if rifsBalance.BalanceMap[MINUTES+OUTBOUND][0].Value != 0 ||
@@ -259,7 +259,7 @@ func TestDebitCreditZeroMinute(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != time.Minute {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -292,8 +292,8 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "tests" ||
cc.Timespans[1].Increments[0].BalanceUuid != "testm" {
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "tests" ||
cc.Timespans[1].Increments[0].BalanceUuids[0] != "testm" {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0], cc.Timespans[1].Increments[0])
}
if rifsBalance.BalanceMap[MINUTES+OUTBOUND][1].Value != 0 ||
@@ -330,7 +330,7 @@ func TestDebitCreditNoCredit(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != time.Minute {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -371,7 +371,7 @@ func TestDebitCreditHasCredit(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != time.Minute {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -407,7 +407,7 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != 10*time.Second {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -448,7 +448,7 @@ func TestDebitCreditMoreTimespans(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != time.Minute {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -486,7 +486,7 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) {
if err != nil {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "testb" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "testb" ||
cc.Timespans[0].Increments[0].Duration != time.Minute {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}
@@ -558,7 +558,7 @@ func TestDebitCreditMoneyOnly(t *testing.T) {
t.Error("Error debiting balance: ", err)
}
if cc.Timespans[0].Increments[0].BalanceUuid != "money" ||
if cc.Timespans[0].Increments[0].BalanceUuids[0] != "money" ||
cc.Timespans[0].Increments[0].Duration != 10*time.Second {
t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0])
}

View File

@@ -297,7 +297,7 @@ func (sm *FSSessionManager) LoopAction(s *Session, cd *engine.CallDescriptor, in
cc = &engine.CallCost{}
cd.LoopIndex = index
cd.Amount = sm.debitPeriod.Seconds()
cd.CallDuration += time.Duration(cd.Amount) * time.Second
cd.CallDuration += sm.debitPeriod
err := sm.connector.MaxDebit(*cd, cc)
if err != nil {
engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err))