mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
Add action type *dynamic_Ranking and update *dynamic_threshold
This commit is contained in:
committed by
Dan Christian Bogos
parent
7bf0d2d162
commit
d9bda57f38
104
engine/action.go
104
engine/action.go
@@ -197,6 +197,7 @@ func init() {
|
||||
actionFuncMap[utils.MetaDynamicDestination] = dynamicDestination
|
||||
actionFuncMap[utils.MetaDynamicFilter] = dynamicFilter
|
||||
actionFuncMap[utils.MetaDynamicRoute] = dynamicRoute
|
||||
actionFuncMap[utils.MetaDynamicRanking] = dynamicRanking
|
||||
}
|
||||
|
||||
func getActionFunc(typ string) (f actionTypeFunc, exists bool) {
|
||||
@@ -1460,6 +1461,7 @@ func remoteSetAccount(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ Sh
|
||||
// 8 Weight: float, should be higher than the threshold weight that triggers this action
|
||||
// 9 ActionIDs: strings separated by "&".
|
||||
// 10 Async: bool
|
||||
// 11 EeIDs: strings separated by "&".
|
||||
// 11 APIOpts: set of key-value pairs (separated by "&").
|
||||
//
|
||||
// Parameters are separated by ";" and must be provided in the specified order.
|
||||
@@ -1477,8 +1479,8 @@ func dynamicThreshold(_ *Account, act *Action, _ Actions, _ *FilterS, ev any,
|
||||
}
|
||||
// Parse action parameters based on the predefined format.
|
||||
params := strings.Split(act.ExtraParameters, utils.InfieldSep)
|
||||
if len(params) != 12 {
|
||||
return errors.New(fmt.Sprintf("invalid number of parameters <%d> expected 12", len(params)))
|
||||
if len(params) != 13 {
|
||||
return errors.New(fmt.Sprintf("invalid number of parameters <%d> expected 13", len(params)))
|
||||
}
|
||||
// parse dynamic parameters
|
||||
for i := range params {
|
||||
@@ -1560,9 +1562,13 @@ func dynamicThreshold(_ *Account, act *Action, _ Actions, _ *FilterS, ev any,
|
||||
return err
|
||||
}
|
||||
}
|
||||
// populate Threshold's APIOpts
|
||||
// populate Threshold's EeIDs
|
||||
if params[11] != utils.EmptyString {
|
||||
if err := parseParamStringToMap(params[11], thProf.APIOpts); err != nil {
|
||||
thProf.EeIDs = strings.Split(params[11], utils.ANDSep)
|
||||
}
|
||||
// populate Threshold's APIOpts
|
||||
if params[12] != utils.EmptyString {
|
||||
if err := parseParamStringToMap(params[12], thProf.APIOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -2174,10 +2180,10 @@ func dynamicFilter(_ *Account, act *Action, _ Actions, _ *FilterS, ev any,
|
||||
// 9 RouteRatingPlanIDs: strings separated by "&".
|
||||
// 10 RouteResourceIDs: strings separated by "&".
|
||||
// 11 RouteStatIDs: strings separated by "&".
|
||||
// 12 RouteWeight: string
|
||||
// 13 RouteBlocker: string
|
||||
// 12 RouteWeight: float
|
||||
// 13 RouteBlocker: bool
|
||||
// 14 RouteParameters: string
|
||||
// 15 Weight: string
|
||||
// 15 Weight: float
|
||||
// 16 APIOpts: set of key-value pairs (separated by "&").
|
||||
//
|
||||
// Parameters are separated by ";" and must be provided in the specified order.
|
||||
@@ -2294,3 +2300,87 @@ func dynamicRoute(_ *Account, act *Action, _ Actions, _ *FilterS, ev any,
|
||||
var reply string
|
||||
return connMgr.Call(context.Background(), connCfg.ConnIDs, utils.APIerSv1SetRouteProfile, route, &reply)
|
||||
}
|
||||
|
||||
// dynamicRanking processes the `ExtraParameters` field from the action to
|
||||
// construct a RankingProfile
|
||||
//
|
||||
// The ExtraParameters field format is expected as follows:
|
||||
//
|
||||
// 0 Tenant: string
|
||||
// 1 ID: string
|
||||
// 2 Schedule: string
|
||||
// 3 StatIDs: strings separated by "&".
|
||||
// 4 MetricIDs: strings separated by "&".
|
||||
// 5 Sorting: string
|
||||
// 6 SortingParameters: strings separated by "&".
|
||||
// 7 Stored: bool
|
||||
// 8 ThresholdIDs: strings separated by "&".
|
||||
// 9 APIOpts: set of key-value pairs (separated by "&").
|
||||
//
|
||||
// Parameters are separated by ";" and must be provided in the specified order.
|
||||
func dynamicRanking(_ *Account, act *Action, _ Actions, _ *FilterS, ev any,
|
||||
_ SharedActionsData, connCfg ActionConnCfg) (err error) {
|
||||
cgrEv, canCast := ev.(*utils.CGREvent)
|
||||
if !canCast {
|
||||
return errors.New("Couldn't cast event to CGREvent")
|
||||
}
|
||||
dP := utils.MapStorage{ // create DataProvider from event
|
||||
utils.MetaReq: cgrEv.Event,
|
||||
utils.MetaTenant: cgrEv.Tenant,
|
||||
utils.MetaNow: time.Now(),
|
||||
utils.MetaOpts: cgrEv.APIOpts,
|
||||
}
|
||||
// Parse action parameters based on the predefined format.
|
||||
params := strings.Split(act.ExtraParameters, utils.InfieldSep)
|
||||
if len(params) != 10 {
|
||||
return errors.New(fmt.Sprintf("invalid number of parameters <%d> expected 10", len(params)))
|
||||
}
|
||||
// parse dynamic parameters
|
||||
for i := range params {
|
||||
if params[i], err = utils.ParseParamForDataProvider(params[i], dP, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Prepare request arguments based on provided parameters.
|
||||
ranking := &RankingProfileWithAPIOpts{
|
||||
RankingProfile: &RankingProfile{
|
||||
Tenant: params[0],
|
||||
ID: params[1],
|
||||
Schedule: params[2],
|
||||
Sorting: params[5],
|
||||
},
|
||||
APIOpts: make(map[string]any),
|
||||
}
|
||||
// populate Ranking's StatIDs
|
||||
if params[3] != utils.EmptyString {
|
||||
ranking.StatIDs = strings.Split(params[3], utils.ANDSep)
|
||||
}
|
||||
// populate Ranking's MetricIDs
|
||||
if params[4] != utils.EmptyString {
|
||||
ranking.MetricIDs = strings.Split(params[4], utils.ANDSep)
|
||||
}
|
||||
// populate Ranking's SortingParameters
|
||||
if params[6] != utils.EmptyString {
|
||||
ranking.SortingParameters = strings.Split(params[6], utils.ANDSep)
|
||||
}
|
||||
// populate Ranking's Stored
|
||||
if params[7] != utils.EmptyString {
|
||||
ranking.Stored, err = strconv.ParseBool(params[7])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// populate Ranking's ThresholdIDs
|
||||
if params[8] != utils.EmptyString {
|
||||
ranking.ThresholdIDs = strings.Split(params[8], utils.ANDSep)
|
||||
}
|
||||
// populate Ranking's APIOpts
|
||||
if params[9] != utils.EmptyString {
|
||||
if err := parseParamStringToMap(params[9], ranking.APIOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// create the RankingProfile based on the populated parameters
|
||||
var reply string
|
||||
return connMgr.Call(context.Background(), connCfg.ConnIDs, utils.APIerSv1SetRankingProfile, ranking, &reply)
|
||||
}
|
||||
|
||||
@@ -4982,12 +4982,13 @@ func TestDynamicThreshold(t *testing.T) {
|
||||
Weight: 10,
|
||||
ActionIDs: []string{"ACT_LOG_WARNING"},
|
||||
Async: true,
|
||||
EeIDs: []string{"eeID1", "eeID2"},
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
"key": "value",
|
||||
},
|
||||
},
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;*string:~*req.Account:1001;2014-07-29T15:00:00Z;1;1;1s;true;10;ACT_LOG_WARNING;true;key:value",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;*string:~*req.Account:1001;2014-07-29T15:00:00Z;1;1;1s;true;10;ACT_LOG_WARNING;true;eeID1&eeID2;key:value",
|
||||
},
|
||||
{
|
||||
name: "SuccessfulRequestWithDynamicPaths",
|
||||
@@ -5008,12 +5009,13 @@ func TestDynamicThreshold(t *testing.T) {
|
||||
Weight: 10,
|
||||
ActionIDs: []string{"ACT_LOG_WARNING"},
|
||||
Async: true,
|
||||
EeIDs: []string{"eeID1", "eeID2"},
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
"key": "value",
|
||||
},
|
||||
},
|
||||
extraParams: "*tenant;THD_ACNT_<~*req.Account>;*string:~*req.Account:<~*req.Account>;*now&3000-07-29T15:00:00Z;1;1;1s;true;10;ACT_LOG_WARNING;true;key:value",
|
||||
extraParams: "*tenant;THD_ACNT_<~*req.Account>;*string:~*req.Account:<~*req.Account>;*now&3000-07-29T15:00:00Z;1;1;1s;true;10;ACT_LOG_WARNING;true;eeID1&eeID2;key:value",
|
||||
},
|
||||
{
|
||||
name: "SuccessfulRequestEmptyFields",
|
||||
@@ -5031,69 +5033,70 @@ func TestDynamicThreshold(t *testing.T) {
|
||||
Weight: 0,
|
||||
ActionIDs: nil,
|
||||
Async: false,
|
||||
EeIDs: nil,
|
||||
},
|
||||
APIOpts: map[string]any{},
|
||||
},
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;;;;;;;;;;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;;;;;;;;;;;",
|
||||
},
|
||||
{
|
||||
name: "MissingConns",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: "MANDATORY_IE_MISSING: [connIDs]",
|
||||
},
|
||||
{
|
||||
name: "WrongNumberOfParams",
|
||||
extraParams: "tenant;;1;",
|
||||
expectedErr: "invalid number of parameters <4> expected 12",
|
||||
expectedErr: "invalid number of parameters <4> expected 13",
|
||||
},
|
||||
{
|
||||
name: "ActivationIntervalLengthFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z&&;1;1;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z&&;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: utils.ErrUnsupportedFormat.Error(),
|
||||
},
|
||||
{
|
||||
name: "ActivationIntervalBadStringFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`,
|
||||
},
|
||||
{
|
||||
name: "ActivationIntervalBadStringFail2",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z&bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z&bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`,
|
||||
},
|
||||
{
|
||||
name: "MaxHitsFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;BadString;1;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;BadString;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `strconv.Atoi: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "MinHitsFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;BadString;1s;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;BadString;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `strconv.Atoi: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "MinSleepFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;BadString;false;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;BadString;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `time: invalid duration "BadString"`,
|
||||
},
|
||||
{
|
||||
name: "BlockerFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;BadString;10;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;BadString;10;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `strconv.ParseBool: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "WeightFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;BadString;ACT_LOG_WARNING;true;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;BadString;ACT_LOG_WARNING;true;eeID1&eeID2;",
|
||||
expectedErr: `strconv.ParseFloat: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "AsyncFail",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;BadString;",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;BadString;eeID1&eeID2;",
|
||||
expectedErr: `strconv.ParseBool: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "InvalidOptsMap",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;true;opt",
|
||||
extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;opt",
|
||||
expectedErr: "invalid key-value pair: opt",
|
||||
},
|
||||
}
|
||||
@@ -6476,3 +6479,153 @@ func TestDynamicRoute(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicRanking(t *testing.T) {
|
||||
tempConn := connMgr
|
||||
tmpDm := dm
|
||||
tmpCache := Cache
|
||||
defer func() {
|
||||
config.SetCgrConfig(config.NewDefaultCGRConfig())
|
||||
SetConnManager(tempConn)
|
||||
dm = tmpDm
|
||||
Cache = tmpCache
|
||||
}()
|
||||
Cache.Clear(nil)
|
||||
var rpwo *RankingProfileWithAPIOpts
|
||||
ccMock := &ccMock{
|
||||
calls: map[string]func(ctx *context.Context, args any, reply any) error{
|
||||
utils.APIerSv1SetRankingProfile: func(ctx *context.Context, args, reply any) error {
|
||||
var canCast bool
|
||||
if rpwo, canCast = args.(*RankingProfileWithAPIOpts); !canCast {
|
||||
return fmt.Errorf("couldnt cast")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
connID := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier)
|
||||
clientconn := make(chan birpc.ClientConnector, 1)
|
||||
clientconn <- ccMock
|
||||
NewConnManager(config.NewDefaultCGRConfig(), map[string]chan birpc.ClientConnector{
|
||||
connID: clientconn,
|
||||
})
|
||||
testcases := []struct {
|
||||
name string
|
||||
extraParams string
|
||||
connIDs []string
|
||||
expRpwo *RankingProfileWithAPIOpts
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "SuccessfulRequest",
|
||||
connIDs: []string{connID},
|
||||
expRpwo: &RankingProfileWithAPIOpts{
|
||||
RankingProfile: &RankingProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "RKNG_ACNT_1001",
|
||||
Schedule: "@every 15m",
|
||||
StatIDs: []string{"Stats2", "Stats3", "Stats4"},
|
||||
MetricIDs: []string{"Metric1", "Metric3"},
|
||||
Sorting: "*asc",
|
||||
SortingParameters: []string{"metricA:true", "metricB:false"},
|
||||
Stored: true,
|
||||
ThresholdIDs: []string{"THD1", "THD2"},
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
"key": "value",
|
||||
},
|
||||
},
|
||||
extraParams: "cgrates.org;RKNG_ACNT_1001;@every 15m;Stats2&Stats3&Stats4;Metric1&Metric3;*asc;metricA:true&metricB:false;true;THD1&THD2;key:value",
|
||||
},
|
||||
{
|
||||
name: "SuccessfulRequestWithDynamicPaths",
|
||||
connIDs: []string{connID},
|
||||
expRpwo: &RankingProfileWithAPIOpts{
|
||||
RankingProfile: &RankingProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "RKNG_ACNT_1001",
|
||||
Schedule: "@every 15m",
|
||||
StatIDs: []string{"Stats2", "Stats3", "Stats4"},
|
||||
MetricIDs: []string{"Metric1", "Metric3"},
|
||||
Sorting: "*asc",
|
||||
SortingParameters: []string{"metricA:true", "metricB:false"},
|
||||
Stored: true,
|
||||
ThresholdIDs: []string{"THD1", "THD2"},
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
"key": "value",
|
||||
},
|
||||
},
|
||||
extraParams: "*tenant;RKNG_ACNT_<~*req.Account>;@every 15m;Stats2&Stats3&Stats4;Metric1&Metric3;*asc;metricA:true&metricB:false;true;THD1&THD2;key:value",
|
||||
},
|
||||
{
|
||||
name: "SuccessfulRequestEmptyFields",
|
||||
connIDs: []string{connID},
|
||||
expRpwo: &RankingProfileWithAPIOpts{
|
||||
RankingProfile: &RankingProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "RKNG_ACNT_1001",
|
||||
Schedule: "@every 15m",
|
||||
StatIDs: nil,
|
||||
MetricIDs: nil,
|
||||
Sorting: "",
|
||||
SortingParameters: nil,
|
||||
Stored: false,
|
||||
ThresholdIDs: nil,
|
||||
},
|
||||
APIOpts: map[string]any{},
|
||||
},
|
||||
extraParams: "cgrates.org;RKNG_ACNT_1001;@every 15m;;;;;;;",
|
||||
},
|
||||
{
|
||||
name: "MissingConns",
|
||||
extraParams: "cgrates.org;RKNG_ACNT_1001;@every 15m;Stats2&Stats3&Stats4;Metric1&Metric3;*asc;metricA:true&metricB:false;true;THD1&THD2;key:value",
|
||||
expectedErr: "MANDATORY_IE_MISSING: [connIDs]",
|
||||
},
|
||||
{
|
||||
name: "WrongNumberOfParams",
|
||||
extraParams: "tenant;RKNG;;",
|
||||
expectedErr: "invalid number of parameters <4> expected 10",
|
||||
},
|
||||
{
|
||||
name: "RankingStoredFail",
|
||||
extraParams: "cgrates.org;RKNG_ACNT_1001;@every 15m;Stats2&Stats3&Stats4;Metric1&Metric3;*asc;metricA:true&metricB:false;BadString;THD1&THD2;key:value",
|
||||
expectedErr: `strconv.ParseBool: parsing "BadString": invalid syntax`,
|
||||
},
|
||||
{
|
||||
name: "InvalidOptsMap",
|
||||
extraParams: "cgrates.org;RKNG_ACNT_1001;@every 15m;Stats2&Stats3&Stats4;Metric1&Metric3;*asc;metricA:true&metricB:false;true;THD1&THD2;opt",
|
||||
expectedErr: "invalid key-value pair: opt",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
action := &Action{ExtraParameters: tc.extraParams}
|
||||
ev := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "evID",
|
||||
Time: &time.Time{},
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
},
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
rpwo = nil
|
||||
})
|
||||
err := dynamicRanking(nil, action, nil, nil, ev,
|
||||
SharedActionsData{}, ActionConnCfg{
|
||||
ConnIDs: tc.connIDs,
|
||||
})
|
||||
if tc.expectedErr != "" {
|
||||
if err == nil || err.Error() != tc.expectedErr {
|
||||
t.Errorf("expected error <%v>, received <%v>", tc.expectedErr, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rpwo, tc.expRpwo) {
|
||||
t.Errorf("Expected <%v>\nReceived\n<%v>", utils.ToJSON(tc.expRpwo), utils.ToJSON(rpwo))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,12 +156,12 @@ func TestDynamicAccountWithStatsAndThreshold(t *testing.T) {
|
||||
// dynamic threshold for already created dynamic accounts, needed so we can ignore matching thresholds the events (which dont come from stats) where an account has already been dynamicaly created by the initial threhold THD_DYNAMIC_STATS_AND_THRESHOLD_INIT. The threshold itself is only used for blocking
|
||||
Identifier: utils.MetaDynamicThreshold,
|
||||
// get tenant and accountID from event, threshold triggers when the event account matches the already dynamicaly created account. If it matches the filter, it will block other thresholds from matching with the event. Make sure dynamic thresholds weight is higher than the initiative threshold THD_DYNAMIC_STATS_AND_THRESHOLD_INIT
|
||||
ExtraParameters: "*tenant;THD_BLOCKER_ACNT_<~*req.Account>;*string:~*opts.*accountID:<~*req.Account>;*now;-1;1;;true;3;;true;",
|
||||
ExtraParameters: "*tenant;THD_BLOCKER_ACNT_<~*req.Account>;*string:~*opts.*accountID:<~*req.Account>;*now;-1;1;;true;3;;true;;",
|
||||
},
|
||||
{
|
||||
Identifier: utils.MetaDynamicThreshold,
|
||||
// get tenant and accountID from event, threshold triggers when sum of statID hits 100, after triggers the action, the threshold will be disabled for 5 seconds, make sure dynamic thresholds weight is higher than the initiative threshold THD_DYNAMIC_STATS_AND_THRESHOLD_INIT and blocker threshold THD_BLOCKER_ACNT_<~*req.Account>
|
||||
ExtraParameters: "*tenant;THD_ACNT_<~*req.Account>;*string:~*req.StatID:Stat_<~*req.Account>&*string:~*req.*sum#1:100;*now;-1;1;5s;true;4;ACT_BLOCK_ACC&ACT_DYN_ACT_PLAN_ACC_ENABLE;true;",
|
||||
ExtraParameters: "*tenant;THD_ACNT_<~*req.Account>;*string:~*req.StatID:Stat_<~*req.Account>&*string:~*req.*sum#1:100;*now;-1;1;5s;true;4;ACT_BLOCK_ACC&ACT_DYN_ACT_PLAN_ACC_ENABLE;true;;",
|
||||
},
|
||||
{
|
||||
Identifier: utils.MetaDynamicStats,
|
||||
|
||||
@@ -127,7 +127,7 @@ func testDynThdSetAction(t *testing.T) {
|
||||
ActionsId: "DYNAMIC_THRESHOLD_ACTION",
|
||||
Actions: []*utils.TPAction{{
|
||||
Identifier: utils.MetaDynamicThreshold,
|
||||
ExtraParameters: "cgrates.org;DYNAMICLY_THR_<~*req.ID>;*string:~*opts.*eventType:AccountUpdate;;1;;;true;10;;true;~*opts",
|
||||
ExtraParameters: "cgrates.org;DYNAMICLY_THR_<~*req.ID>;*string:~*opts.*eventType:AccountUpdate;;1;;;true;10;;true;;~*opts",
|
||||
}}}
|
||||
if err := dynThdRpc.Call(context.Background(), utils.APIerSv2SetActions,
|
||||
act, &reply); err != nil {
|
||||
|
||||
@@ -1214,6 +1214,7 @@ const (
|
||||
MetaDynamicDestination = "*dynamic_destination"
|
||||
MetaDynamicFilter = "*dynamic_filter"
|
||||
MetaDynamicRoute = "*dynamic_route"
|
||||
MetaDynamicRanking = "*dynamic_ranking"
|
||||
ActionID = "ActionID"
|
||||
ActionType = "ActionType"
|
||||
ActionValue = "ActionValue"
|
||||
|
||||
Reference in New Issue
Block a user