tests for rating info activation times

This commit is contained in:
Radu Ioan Fericean
2013-11-18 19:35:53 +02:00
parent 352540ab04
commit a483d2304e
5 changed files with 83 additions and 42 deletions

View File

@@ -21,6 +21,7 @@ package engine
import (
"errors"
"fmt"
"github.com/cgrates/cgrates/cache2go"
"github.com/cgrates/cgrates/history"
"github.com/cgrates/cgrates/utils"
@@ -136,12 +137,10 @@ func (cd *CallDescriptor) getUserBalance() (ub *UserBalance, err error) {
Restores the activation periods for the specified prefix from storage.
*/
func (cd *CallDescriptor) LoadRatingPlans() (err error) {
err = cd.getRatingPlansForPrefix(cd.GetKey(), 1)
if err != nil {
// try general fallback
fallbackKey := fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, FALLBACK_SUBJECT)
err = cd.getRatingPlansForPrefix(cd.GetKey(cd.Subject), 1)
if err != nil || !cd.continousRatingInfos() {
// use the default subject
err = cd.getRatingPlansForPrefix(fallbackKey, 1)
err = cd.getRatingPlansForPrefix(cd.GetKey(FALLBACK_SUBJECT), 1)
}
//load the rating plans
if err != nil || !cd.continousRatingInfos() {
@@ -164,6 +163,7 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
}
if err = rp.GetRatingPlansForPrefix(cd); err != nil || !cd.continousRatingInfos() {
// try rating profile fallback
recursionDepth++
for index := 0; index < len(cd.RatingInfos); index++ {
ri := cd.RatingInfos[index]
if len(ri.RateIntervals) > 0 {
@@ -171,8 +171,12 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
continue
}
if len(ri.FallbackKeys) > 0 {
recursionDepth++
tempCD := &CallDescriptor{}
tempCD := &CallDescriptor{
TOR: cd.TOR,
Direction: cd.Direction,
Tenant: cd.Tenant,
Destination: cd.Destination,
}
if index == 0 {
tempCD.TimeStart = cd.TimeStart
} else {
@@ -189,6 +193,10 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
}
// extract the rate infos and break
for newIndex, newRI := range tempCD.RatingInfos {
// check if the new ri is filled
if len(newRI.RateIntervals) == 0 {
continue
}
if newIndex == 0 {
cd.RatingInfos[index] = newRI
} else {
@@ -254,8 +262,8 @@ func (cd *CallDescriptor) addRatingInfos(ris RatingInfos) bool {
Constructs the key for the storage lookup.
The prefixLen is limiting the length of the destination prefix.
*/
func (cd *CallDescriptor) GetKey() string {
return fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, cd.Subject)
func (cd *CallDescriptor) GetKey(subject string) string {
return fmt.Sprintf("%s:%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, subject)
}
/*

View File

@@ -341,7 +341,7 @@ func BenchmarkStorageGetting(b *testing.B) {
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
b.StartTimer()
for i := 0; i < b.N; i++ {
storageGetter.GetRatingProfile(cd.GetKey())
storageGetter.GetRatingProfile(cd.GetKey(cd.Subject))
}
}

View File

@@ -88,6 +88,8 @@ EVENING,P2,WORKDAYS_18,10
EVENING,P2,WEEKENDS,10
TDRT,T1,WORKDAYS_00,10
TDRT,T2,WORKDAYS_00,10
G,RT_STANDARD,WORKDAYS_00,10
R,P1,WORKDAYS_00,10
`
ratingProfiles = `
CUSTOMER_1,0,*out,rif:from:tm,2012-01-01T00:00:00Z,PREMIUM,danb
@@ -102,6 +104,10 @@ 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;danb
vdf,0,*out,fallback1,2013-11-18T13:45:00Z,G,fallback2
vdf,0,*out,fallback1,2013-11-18T13:46:00Z,G,fallback2
vdf,0,*out,fallback1,2013-11-18T13:47:00Z,G,fallback2
vdf,0,*out,fallback2,2013-11-18T13:45:00Z,R,rif
`
actions = `
MINI,*topup_reset,*monetary,*out,10,*unlimited,,,10,,10
@@ -240,68 +246,68 @@ func TestLoadRates(t *testing.T) {
t.Error("Failed to load rates: ", csvr.rates)
}
rate := csvr.rates["R1"].RateSlots[0]
expctRs,err := utils.NewRateSlot(0, 0.2, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2)
expctRs, err := utils.NewRateSlot(0, 0.2, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2)
if err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate, expctRs)
t.Error("Error loading rate: ", rate, expctRs)
}
rate = csvr.rates["R2"].RateSlots[0]
if expctRs,err = utils.NewRateSlot(0, 0.1, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2); err != nil {
if expctRs, err = utils.NewRateSlot(0, 0.1, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
rate = csvr.rates["R3"].RateSlots[0]
if expctRs, err = utils.NewRateSlot( 0, 0.05, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2 ); err != nil {
if expctRs, err = utils.NewRateSlot(0, 0.05, "60s", "1s", "0", utils.ROUNDING_MIDDLE, 2); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
rate = csvr.rates["R4"].RateSlots[0]
if expctRs, err = utils.NewRateSlot( 1, 1.0, "1s", "1s", "0", utils.ROUNDING_UP, 2 ); err != nil {
if expctRs, err = utils.NewRateSlot(1, 1.0, "1s", "1s", "0", utils.ROUNDING_UP, 2); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
rate = csvr.rates["R5"].RateSlots[0]
if expctRs, err = utils.NewRateSlot( 0, 0.5, "1s", "1s", "0", utils.ROUNDING_DOWN, 2 ); err != nil {
if expctRs, err = utils.NewRateSlot(0, 0.5, "1s", "1s", "0", utils.ROUNDING_DOWN, 2); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[0]
if expctRs, err = utils.NewRateSlot( 0, 1, "1s", "60s", "0s", utils.ROUNDING_UP, 4 ); err != nil {
if expctRs, err = utils.NewRateSlot(0, 1, "1s", "60s", "0s", utils.ROUNDING_UP, 4); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[1]
if expctRs, err = utils.NewRateSlot( 0, 1, "1s", "1s", "60s", utils.ROUNDING_UP, 4 ); err != nil {
if expctRs, err = utils.NewRateSlot(0, 1, "1s", "1s", "60s", utils.ROUNDING_UP, 4); err != nil {
t.Error("Error loading rate: ", rate, err.Error())
} else if !reflect.DeepEqual(rate, expctRs) ||
rate.RateUnitDuration() != expctRs.RateUnitDuration() ||
rate.RateIncrementDuration() != expctRs.RateIncrementDuration() ||
rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() {
t.Error("Error loading rate: ", rate)
t.Error("Error loading rate: ", rate)
}
}
@@ -418,7 +424,7 @@ func TestLoadDestinationRates(t *testing.T) {
}
func TestLoadDestinationRateTimings(t *testing.T) {
if len(csvr.ratingPlans) != 5 {
if len(csvr.ratingPlans) != 7 {
t.Error("Failed to load rate timings: ", csvr.ratingPlans)
}
rplan := csvr.ratingPlans["STANDARD"]
@@ -538,7 +544,7 @@ func TestLoadDestinationRateTimings(t *testing.T) {
}
func TestLoadRatingProfiles(t *testing.T) {
if len(csvr.ratingProfiles) != 10 {
if len(csvr.ratingProfiles) != 12 {
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
}
rp := csvr.ratingProfiles["*out:test:0:trp"]

View File

@@ -100,10 +100,9 @@ func (ris RatingInfos) Sort() {
sort.Sort(ris)
}
// TODO: what happens if there is no match for part of the call
func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (err error) {
var ris RatingInfos
for _, rpa := range rp.RatingPlanActivations.GetActiveForCall(cd) {
for index, rpa := range rp.RatingPlanActivations.GetActiveForCall(cd) {
rpl, err := storageGetter.GetRatingPlan(rpa.RatingPlanId)
if err != nil || rpl == nil {
Logger.Err(fmt.Sprintf("Error checking destination: %v", err))
@@ -124,6 +123,10 @@ func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (err error)
rps = rpl.RateIntervalList(dId)
}
}
// check if it's the first ri and add a blank one for the initial part not covered
if index == 0 && cd.TimeStart.Before(rpa.ActivationTime) {
ris = append(ris, &RatingInfo{"", "", cd.TimeStart, nil, []string{cd.GetKey(FALLBACK_SUBJECT)}})
}
if bestPrecision > 0 {
ris = append(ris, &RatingInfo{rp.Id, cd.Destination[:bestPrecision], rpa.ActivationTime, rps, rpa.FallbackKeys})
} else {

View File

@@ -20,20 +20,44 @@ package engine
import (
"testing"
"time"
)
func TestRpAddAPIfNotPresent(t *testing.T) {
/* ap1 := &RatingPlan{Id: "test1"}
ap2 := &RatingPlan{Id: "test1"}
ap3 := &RatingPlan{Id: "test2"}
rp := &RatingProfile{}
rp.AddRatingPlanIfNotPresent("test", ap1)
rp.AddRatingPlanIfNotPresent("test", ap2)
if len(rp.DestinationMap["test"]) != 1 {
t.Error("Wronfully appended activation period ;)", len(rp.DestinationMap["test"]))
}
rp.AddRatingPlanIfNotPresent("test", ap3)
if len(rp.DestinationMap["test"]) != 2 {
t.Error("Wronfully not appended activation period ;)", len(rp.DestinationMap["test"]))
}*/
func TestGetRatingProfileForPrefix(t *testing.T) {
cd := &CallDescriptor{
TimeStart: time.Date(2013, 11, 18, 13, 45, 1, 0, time.UTC),
TimeEnd: time.Date(2013, 11, 18, 13, 47, 30, 0, time.UTC),
Tenant: "vdf",
TOR: "0",
Direction: OUTBOUND,
Subject: "fallback1",
Destination: "0256098",
}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 3 || !cd.continousRatingInfos() {
t.Logf("0: %+v", cd.RatingInfos[0])
t.Logf("1: %+v", cd.RatingInfos[1])
t.Logf("2: %+v", cd.RatingInfos[2])
t.Errorf("Error loading rating information: %+v %+v", cd.RatingInfos, cd.continousRatingInfos())
}
}
func TestGetRatingProfileForPrefixFirstEmpty(t *testing.T) {
cd := &CallDescriptor{
TimeStart: time.Date(2013, 11, 18, 13, 44, 1, 0, time.UTC),
TimeEnd: time.Date(2013, 11, 18, 13, 47, 30, 0, time.UTC),
Tenant: "vdf",
TOR: "0",
Direction: OUTBOUND,
Subject: "fallback1",
Destination: "0256098",
}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 4 || !cd.continousRatingInfos() {
t.Logf("0: %+v", cd.RatingInfos[0])
t.Logf("1: %+v", cd.RatingInfos[1])
t.Logf("2: %+v", cd.RatingInfos[2])
t.Logf("3: %+v", cd.RatingInfos[3])
t.Errorf("Error loading rating information: %+v %+v", cd.RatingInfos, cd.continousRatingInfos())
}
}