Added ratePRofileRatesFOrEvent apis + tests

This commit is contained in:
porosnicuadrian
2022-02-11 17:10:14 +02:00
committed by Dan Christian Bogos
parent f5f6dd746a
commit dcdd696932
7 changed files with 207 additions and 14 deletions

View File

@@ -268,6 +268,11 @@ func (rSv1 *RateSv1) RateProfilesForEvent(ctx *context.Context, args *utils.CGRE
return rSv1.rS.V1RateProfilesForEvent(ctx, args, rpIDs)
}
// RateProfilesForEvent returns the list of rates that are matching the event from a specific profile
func (rSv1 *RateSv1) RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREvent, rateIDs *[]string) (err error) {
return rSv1.rS.V1RateProfileRatesForEvent(ctx, args, rateIDs)
}
// CostForEvent returs the costs for the event and all the rate profile information
func (rSv1 *RateSv1) CostForEvent(ctx *context.Context, args *utils.CGREvent, rpCost *utils.RateProfileCost) (err error) {
return rSv1.rS.V1CostForEvent(ctx, args, rpCost)

View File

@@ -76,6 +76,7 @@ var (
testRateProfileSetMultipleRatesInProfile,
testRateProfileUpdateProfileRatesOverwrite,
testRateProfilesForEventMatchingEvents,
testRateProfileRatesForEventMatchingEvents,
testRateSKillEngine,
}
)
@@ -1999,21 +2000,18 @@ func testRateProfilesForEventMatchingEvents(t *testing.T) {
}
ratePrf4 := &utils.APIRateProfile{
RateProfile: &utils.RateProfile{
Tenant: utils.CGRateSorg,
ID: "RT_104",
FilterIDs: []string{"*exists:~*req.Destination:"},
MinCost: utils.NewDecimal(22, 2),
MaxCost: utils.NewDecimal(500000, 6),
MaxCostStrategy: "*free",
Tenant: utils.CGRateSorg,
ID: "RT_104",
FilterIDs: []string{"*exists:~*req.Destination:"},
Rates: map[string]*utils.Rate{
"RT_Destination": {
ID: "RT_Destination",
"RT_Everytime": {
ID: "RT_Everytime",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
ActivationTimes: "* 16 * * *",
ActivationTimes: "* 14 * * *",
IntervalRates: []*utils.IntervalRate{
{
IntervalStart: utils.NewDecimal(0, 0),
@@ -2149,6 +2147,135 @@ func testRateProfilesForEventMatchingEvents(t *testing.T) {
}
}
func testRateProfileRatesForEventMatchingEvents(t *testing.T) {
// now for 2 of our profiles, we will set some rates and see what rates are matching our event
ratePrf1 := &utils.APIRateProfile{
RateProfile: &utils.RateProfile{
Tenant: utils.CGRateSorg,
ID: "RT_CGR202",
//FilterIDs: []string{"*lte:~*opts.*usage:2m"},
Rates: map[string]*utils.Rate{
"RT_ALWAYS": {
ID: "RT_ALWAYS",
FilterIDs: []string{"*prefix:~*req.Destination:2023", "*string:~*opts.*usage:1m"},
ActivationTimes: "* * * * *",
IntervalRates: []*utils.IntervalRate{
{
IntervalStart: utils.NewDecimal(0, 0),
FixedFee: utils.NewDecimal(22, 2),
Increment: utils.NewDecimal(int64(5*time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(5*time.Second), 0),
Unit: utils.NewDecimal(int64(time.Minute), 0),
},
},
},
"RT_WEEKEND": {
ID: "RT_WEEKEND",
ActivationTimes: "* * * * 5-6",
FilterIDs: []string{"*prefix:~*req.Destination:2023"},
IntervalRates: []*utils.IntervalRate{
{
IntervalStart: utils.NewDecimal(0, 0),
Increment: utils.NewDecimal(int64(time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(time.Second), 0),
Unit: utils.NewDecimal(int64(time.Minute), 0),
},
},
},
"RT_SPECIAL": {
ID: "RT_SPECIAL",
ActivationTimes: "* 12 * * *",
FilterIDs: []string{"*string:~*req.Account:2021",
"*string:~*req.Destination:2023"},
IntervalRates: []*utils.IntervalRate{
{
IntervalStart: utils.NewDecimal(int64(50*time.Second), 0),
Increment: utils.NewDecimal(int64(2*time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(2*time.Second), 0),
Unit: utils.NewDecimal(int64(time.Minute), 0),
},
},
},
"RT_DIFFERENT": {
ID: "RT_DIFFERENT",
ActivationTimes: "10 12 * * *",
//FilterIDs: []string{"*lte:~*opts.*usage:2m"},
IntervalRates: []*utils.IntervalRate{
{
IntervalStart: utils.NewDecimal(int64(50*time.Second), 0),
Increment: utils.NewDecimal(int64(2*time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(2*time.Second), 0),
Unit: utils.NewDecimal(int64(time.Minute), 0),
},
},
},
},
},
}
var reply string
if err := rateSRPC.Call(context.Background(), utils.AdminSv1SetRateProfile,
ratePrf1, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
expected := []string{"RT_DIFFERENT"}
var rateIDs []string
if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent,
&utils.CGREvent{
Tenant: "cgrates.org",
Event: map[string]interface{}{
"Account": "2021",
},
APIOpts: map[string]interface{}{
utils.MetaRateProfileID: "RT_CGR202",
utils.MetaUsage: "1m",
},
}, &rateIDs); err != nil {
t.Error(err)
} else {
sort.Slice(expected, func(i, j int) bool {
return expected[i] < expected[j]
})
sort.Slice(rateIDs, func(i, j int) bool {
return rateIDs[i] < rateIDs[j]
})
if !reflect.DeepEqual(expected, rateIDs) {
t.Errorf("Expected %+v, received %+v", expected, rateIDs)
}
}
/*
expected := []string{"RT_DIFFERENT"}
var rateIDs []string
if err := rateSRPC.Call(context.Background(), utils.RateSv1RateProfileRatesForEvent,
&utils.CGREvent{
Tenant: "cgrates.org",
Event: map[string]interface{}{
"Account": "2021",
utils.Destination: "2023",
},
APIOpts: map[string]interface{}{
utils.MetaRateProfileID: "RT_CGR202",
utils.MetaUsage: "1m",
},
}, &rateIDs); err != nil {
t.Error(err)
} else {
sort.Slice(expected, func(i, j int) bool {
return expected[i] < expected[j]
})
sort.Slice(rateIDs, func(i, j int) bool {
return rateIDs[i] < rateIDs[j]
})
if !reflect.DeepEqual(expected, rateIDs) {
t.Errorf("Expected %+v, received %+v", expected, rateIDs)
}
}
*/
}
//Kill the engine when it is about to be finished
func testRateSKillEngine(t *testing.T) {
if err := engine.KillEngine(100); err != nil {

View File

@@ -107,7 +107,7 @@
{"tag": "Tenant", "path": "Tenant", "type": "*variable", "value": "~*req.0", "mandatory": true},
{"tag": "ID", "path": "ID", "type": "*variable", "value": "~*req.1", "mandatory": true},
{"tag": "FilterIDs", "path": "FilterIDs", "type": "*variable", "value": "~*req.2"},
{"tag": "Weight", "path": "Weight", "type": "*variable", "value": "~*req.3"},
{"tag": "Weights", "path": "Weights", "type": "*variable", "value": "~*req.3"},
{"tag": "Schedule", "path": "Schedule", "type": "*variable", "value": "~*req.4"},
// {"tag": "TargetType", "path": "TargetType", "type": "*variable", "value": "~*req.5"},
{"tag": "TargetIDs", "path": "Targets[<~*req.5>]", "type": "*variable", "value": "~*req.6"},

View File

@@ -13,6 +13,8 @@
"rates": {
"enabled": true,
"prefix_indexed_fields": ["*req.Destination"],
"exists_indexed_fields": ["*req.Destination"],
},
"admins": {

View File

@@ -17,6 +17,8 @@
"rates": {
"enabled": true,
"prefix_indexed_fields": ["*req.Destination"],
"exists_indexed_fields": ["*req.Destination"],
},
"admins": {

View File

@@ -267,6 +267,61 @@ func (rS *RateS) V1RateProfilesForEvent(ctx *context.Context, args *utils.CGREve
return
}
// RateProfilesForEvent returns the list of rates that are matching the event from a specific profile
func (rS *RateS) V1RateProfileRatesForEvent(ctx *context.Context, args *utils.CGREvent, rtIDs *[]string) (err error) {
if args == nil {
return utils.NewErrMandatoryIeMissing(utils.CGREventString)
}
if _, has := args.APIOpts[utils.MetaRateProfileID]; !has {
return utils.NewErrMandatoryIeMissing(utils.MetaRateProfileID)
}
rpID := utils.IfaceAsString(args.APIOpts[utils.MetaRateProfileID])
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = rS.cfg.GeneralCfg().DefaultTenant
}
evNM := args.AsDataProvider()
var rateIDs utils.StringSet
if rateIDs, err = engine.MatchingItemIDsForEvent(ctx,
evNM,
rS.cfg.RateSCfg().RateStringIndexedFields,
rS.cfg.RateSCfg().RatePrefixIndexedFields,
rS.cfg.RateSCfg().RateSuffixIndexedFields,
rS.cfg.RateSCfg().RateExistsIndexedFields,
rS.cfg.RateSCfg().RateNotExistsIndexedFields,
rS.dm,
utils.CacheRateFilterIndexes,
utils.ConcatenatedKey(tnt, rpID),
rS.cfg.RateSCfg().RateIndexedSelects,
rS.cfg.RateSCfg().RateNestedFields,
); err != nil {
return
}
if len(rateIDs) == 0 {
return utils.ErrNotFound
}
var ratesMtched []string
for _, rateID := range rateIDs.AsSlice() {
var rp *utils.RateProfile
if rp, err = rS.dm.GetRateProfile(ctx, tnt, rpID, true, true, utils.NonTransactional); err != nil {
return
}
rate := rp.Rates[rateID]
var pass bool
if pass, err = rS.fltrS.Pass(ctx, tnt, rate.FilterIDs, evNM); err != nil {
return
} else if !pass {
continue
}
ratesMtched = append(ratesMtched, rateID)
}
if len(ratesMtched) == 0 {
return utils.ErrNotFound
}
*rtIDs = ratesMtched
return
}
// V1CostForEvent will be called to calculate the cost for an event
func (rS *RateS) V1CostForEvent(ctx *context.Context, args *utils.CGREvent, rpCost *utils.RateProfileCost) (err error) {
var rPfIDs []string

View File

@@ -381,6 +381,7 @@ const (
MetaEEs = "*ees"
MetaRateS = "*rates"
MetaRateSOverwrite = "*rateSOverwrite"
MetaRateProfileID = "*rateProfileID"
MetaContinue = "*continue"
MetaUp = "*up"
Migrator = "migrator"
@@ -1297,10 +1298,11 @@ const (
)
const (
RateSv1 = "RateSv1"
RateSv1CostForEvent = "RateSv1.CostForEvent"
RateSv1RateProfilesForEvent = "RateSv1.RateProfilesForEvent"
RateSv1Ping = "RateSv1.Ping"
RateSv1 = "RateSv1"
RateSv1CostForEvent = "RateSv1.CostForEvent"
RateSv1RateProfilesForEvent = "RateSv1.RateProfilesForEvent"
RateSv1RateProfileRatesForEvent = "RateSv1.RateProfileRatesForEvent"
RateSv1Ping = "RateSv1.Ping"
)
const (