no default fallback, fixes #146

This commit is contained in:
Radu Ioan Fericean
2015-08-18 23:05:05 +03:00
parent 287767d8fa
commit 7d20097754
6 changed files with 62 additions and 24 deletions

View File

@@ -177,10 +177,12 @@ func (cd *CallDescriptor) getAccount() (ub *Account, err error) {
Restores the activation periods for the specified prefix from storage.
*/
func (cd *CallDescriptor) LoadRatingPlans() (err error) {
err = cd.getRatingPlansForPrefix(cd.GetKey(cd.Subject), 1)
if err != nil || !cd.continousRatingInfos() {
// use the default subject
err = cd.getRatingPlansForPrefix(cd.GetKey(FALLBACK_SUBJECT), 1)
var rec int
err, rec = cd.getRatingPlansForPrefix(cd.GetKey(cd.Subject), 1)
if err == utils.ErrNotFound && rec == 1 {
//if err != nil || !cd.continousRatingInfos() {
// use the default subject only if the initial one was not found
err, _ = cd.getRatingPlansForPrefix(cd.GetKey(FALLBACK_SUBJECT), 1)
}
//load the rating plans
if err != nil || !cd.continousRatingInfos() {
@@ -192,14 +194,13 @@ func (cd *CallDescriptor) LoadRatingPlans() (err error) {
// FIXME: this method is not exhaustive but will cover 99% of cases just good
// it will not cover very long calls with very short activation periods for rates
func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int) (err error) {
func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int) (error, int) {
if recursionDepth > RECURSION_MAX_DEPTH {
err = errors.New("Max fallback recursion depth reached!" + key)
return
return utils.ErrMaxRecursionDepth, recursionDepth
}
rpf, err := ratingStorage.GetRatingProfile(key, false)
if err != nil || rpf == nil {
return err
return utils.ErrNotFound, recursionDepth
}
if err = rpf.GetRatingPlansForPrefix(cd); err != nil || !cd.continousRatingInfos() {
// try rating profile fallback
@@ -228,7 +229,7 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
tempCD.TimeEnd = cd.RatingInfos[index+1].ActivationTime
}
for _, fbk := range ri.FallbackKeys {
if err := tempCD.getRatingPlansForPrefix(fbk, recursionDepth); err != nil {
if err, _ := tempCD.getRatingPlansForPrefix(fbk, recursionDepth); err != nil {
continue
}
// extract the rate infos and break
@@ -256,7 +257,7 @@ func (cd *CallDescriptor) getRatingPlansForPrefix(key string, recursionDepth int
}
}
}
return
return nil, recursionDepth
}
// checks if there is rating info for the entire call duration

View File

@@ -84,6 +84,7 @@ T1,NAT,LANDLINE_OFFPEAK,*middle,4,0,
T2,GERMANY,GBP_72,*middle,4,0,
T2,GERMANY_O2,GBP_70,*middle,4,0,
T2,GERMANY_PREMIUM,GBP_71,*middle,4,0,
GER,GERMANY,R4,*middle,4,0,
DR_UK_Mobile_BIG5_PKG,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5_PKG,*middle,4,,
DR_UK_Mobile_BIG5,DST_UK_Mobile_BIG5,RT_UK_Mobile_BIG5,*middle,4,,
DATA_RATE,*any,LANDLINE_OFFPEAK,*middle,4,0,
@@ -112,6 +113,7 @@ RP_UK,DR_UK_Mobile_BIG5,*any,10
RP_DATA,DATA_RATE,*any,10
RP_MX,MX_DISC,WORKDAYS_00,10
RP_MX,MX_FREE,WORKDAYS_18,10
GER_ONLY,GER,*any,10
ANY_PLAN,DATA_RATE,*any,10
`
ratingProfiles = `
@@ -136,6 +138,7 @@ ANY_PLAN,DATA_RATE,*any,10
*out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,,
*out,cgrates.org,data,rif,2013-01-06T00:00:00Z,RP_DATA,,
*out,cgrates.org,call,max,2013-03-23T00:00:00Z,RP_MX,,
*out,cgrates.org,call,nt,2012-02-28T00:00:00Z,GER_ONLY,,
*in,cgrates.org,LCR_STANDARD,max,2013-03-23T00:00:00Z,RP_MX,,
*out,cgrates.org,call,money,2015-02-28T00:00:00Z,EVENING,,
`
@@ -453,7 +456,7 @@ func TestLoadRates(t *testing.T) {
}
func TestLoadDestinationRates(t *testing.T) {
if len(csvr.destinationRates) != 13 {
if len(csvr.destinationRates) != 14 {
t.Error("Failed to load destinationrates: ", len(csvr.destinationRates))
}
drs := csvr.destinationRates["RT_STANDARD"]
@@ -601,7 +604,7 @@ func TestLoadDestinationRates(t *testing.T) {
}
func TestLoadRatingPlans(t *testing.T) {
if len(csvr.ratingPlans) != 12 {
if len(csvr.ratingPlans) != 13 {
t.Error("Failed to load rating plans: ", len(csvr.ratingPlans))
}
rplan := csvr.ratingPlans["STANDARD"]
@@ -773,7 +776,7 @@ func TestLoadRatingPlans(t *testing.T) {
}
func TestLoadRatingProfiles(t *testing.T) {
if len(csvr.ratingProfiles) != 20 {
if len(csvr.ratingProfiles) != 21 {
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
}
rp := csvr.ratingProfiles["*out:test:0:trp"]

View File

@@ -117,7 +117,7 @@ func TestFallbackWithBackTrace(t *testing.T) {
}
}
func TestFallbackDefault(t *testing.T) {
func TestFallbackNoDefault(t *testing.T) {
cd := &CallDescriptor{
TimeStart: time.Date(2013, 10, 21, 18, 34, 0, 0, time.UTC),
TimeEnd: time.Date(2013, 10, 21, 18, 35, 0, 0, time.UTC),
@@ -127,7 +127,7 @@ func TestFallbackDefault(t *testing.T) {
Subject: "one",
Destination: "0723"}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 1 {
if len(cd.RatingInfos) != 0 {
t.Error("Error restoring activation periods: ", len(cd.RatingInfos))
}
}

View File

@@ -179,17 +179,18 @@ func (rp *RatingProfile) GetRatingPlansForPrefix(cd *CallDescriptor) (err error)
FallbackKeys: rpa.FallbackKeys})
} else {
// add for fallback information
ris = append(ris, &RatingInfo{
MatchedSubject: "",
MatchedPrefix: "",
MatchedDestId: "",
ActivationTime: rpa.ActivationTime,
RateIntervals: nil,
FallbackKeys: rpa.FallbackKeys,
})
if len(rpa.FallbackKeys) > 0 {
ris = append(ris, &RatingInfo{
MatchedSubject: "",
MatchedPrefix: "",
MatchedDestId: "",
ActivationTime: rpa.ActivationTime,
RateIntervals: nil,
FallbackKeys: rpa.FallbackKeys,
})
}
}
}
if len(ris) > 0 {
cd.addRatingInfos(ris)
return

View File

@@ -61,3 +61,35 @@ func TestGetRatingProfileForPrefixFirstEmpty(t *testing.T) {
t.Errorf("Error loading rating information: %+v %+v", cd.RatingInfos, cd.continousRatingInfos())
}
}
func TestGetRatingProfileNotFound(t *testing.T) {
cd := &CallDescriptor{
TimeStart: time.Date(2015, 8, 18, 22, 05, 0, 0, time.UTC),
TimeEnd: time.Date(2015, 8, 18, 22, 06, 30, 0, time.UTC),
Tenant: "vdf",
Category: "0",
Direction: OUTBOUND,
Subject: "no_rating_profile",
Destination: "0256098",
}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 1 || !cd.continousRatingInfos() {
t.Errorf("Error loading rating information: %+v %+v", cd.RatingInfos, cd.continousRatingInfos())
}
}
func TestGetRatingProfileFoundButNoDestination(t *testing.T) {
cd := &CallDescriptor{
TimeStart: time.Date(2015, 8, 18, 22, 05, 0, 0, time.UTC),
TimeEnd: time.Date(2015, 8, 18, 22, 06, 30, 0, time.UTC),
Tenant: "cgrates.org",
Category: "call",
Direction: OUTBOUND,
Subject: "nt",
Destination: "447956",
}
cd.LoadRatingPlans()
if len(cd.RatingInfos) != 0 {
t.Errorf("Error loading rating information: %+v %+v", cd.RatingInfos, cd.continousRatingInfos())
}
}

View File

@@ -17,6 +17,7 @@ var (
ErrNotImplemented = errors.New("NOT_IMPLEMENTED")
ErrNotFound = errors.New("NOT_FOUND")
ErrServerError = errors.New("SERVER_ERROR")
ErrMaxRecursionDepth = errors.New("MAX_RECURSION_DEPTH")
ErrMandatoryIeMissing = errors.New("MANDATORY_IE_MISSING")
ErrExists = errors.New("EXISTS")
ErrBrokenReference = errors.New("BROKEN_REFERENCE")