mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Added profile_runs in attributes
This commit is contained in:
committed by
Dan Christian Bogos
parent
7993a409a5
commit
d3f58e311d
@@ -36,13 +36,12 @@ func TestConfigNewConfigSv1(t *testing.T) {
|
||||
}
|
||||
result := NewConfigSv1(cfg)
|
||||
if !reflect.DeepEqual(expected, result) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, result)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigSetGetConfig(t *testing.T) {
|
||||
//for coverage purposes only
|
||||
var err error
|
||||
cfgTestPath := path.Join(*dataDir, "conf", "samples", "tutinternal")
|
||||
cfg, err := config.NewCGRConfigFromPath(cfgTestPath)
|
||||
if err != nil {
|
||||
@@ -54,16 +53,16 @@ func TestConfigSetGetConfig(t *testing.T) {
|
||||
err = rlcCfg.SetConfig(context.Background(), args, &reply)
|
||||
expected := `OK`
|
||||
if err != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, reply) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
}
|
||||
argsGet := &config.SectionWithAPIOpts{
|
||||
Sections: []string{"attributes"},
|
||||
}
|
||||
var replyGet map[string]interface{}
|
||||
errGet := rlcCfg.GetConfig(context.Background(), argsGet, &replyGet)
|
||||
err = rlcCfg.GetConfig(context.Background(), argsGet, &replyGet)
|
||||
expectedGet := map[string]interface{}{
|
||||
"attributes": map[string]interface{}{
|
||||
"accounts_conns": []string{"*localhost"},
|
||||
@@ -77,13 +76,14 @@ func TestConfigSetGetConfig(t *testing.T) {
|
||||
utils.DefaultOptsCfg: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(1),
|
||||
},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
},
|
||||
}
|
||||
if errGet != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
if err != nil {
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, err)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedGet, replyGet) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expectedGet, replyGet)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", utils.ToJSON(expectedGet), utils.ToJSON(replyGet))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
err = rlcCfg.SetConfig(context.Background(), args, &reply)
|
||||
expected := `OK`
|
||||
if err != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, reply) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
}
|
||||
argsGet := &config.SectionWithAPIOpts{
|
||||
Sections: []string{"attributes"},
|
||||
@@ -141,13 +141,14 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
utils.DefaultOptsCfg: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(1),
|
||||
},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
},
|
||||
}
|
||||
if errGet != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedGet, replyGet) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expectedGet, replyGet)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expectedGet, replyGet)
|
||||
}
|
||||
argsRld := &config.ReloadArgs{
|
||||
DryRun: true,
|
||||
@@ -158,10 +159,10 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
errRld := rlcCfg.ReloadConfig(context.Background(), argsRld, &replyRld)
|
||||
expectedRld := `OK`
|
||||
if err != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, errRld)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, errRld)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedRld, replyRld) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expectedRld, replyRld)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expectedRld, replyRld)
|
||||
}
|
||||
argsGetRld := &config.SectionWithAPIOpts{
|
||||
Sections: []string{"attributes"},
|
||||
@@ -181,13 +182,14 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
utils.DefaultOptsCfg: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(1),
|
||||
},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
},
|
||||
}
|
||||
if errGetRld != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, errGetRld)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, errGetRld)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedGetRld, replyGetRld) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expectedGetRld, replyGetRld)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expectedGetRld, replyGetRld)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,10 +212,10 @@ func TestConfigGetSetConfigFromJSONErr(t *testing.T) {
|
||||
err = rlcCfg.SetConfigFromJSON(context.Background(), args, &reply)
|
||||
expected := "OK"
|
||||
if err != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, reply) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expected, reply)
|
||||
}
|
||||
|
||||
argsGet := &config.SectionWithAPIOpts{
|
||||
@@ -223,12 +225,12 @@ func TestConfigGetSetConfigFromJSONErr(t *testing.T) {
|
||||
}
|
||||
var replyGet string
|
||||
errGet := rlcCfg.GetConfigAsJSON(context.Background(), argsGet, &replyGet)
|
||||
expectedGet := "{\"attributes\":{\"accounts_conns\":[\"*localhost\"],\"default_opts\":{\"*processRuns\":1},\"enabled\":true,\"indexed_selects\":true,\"nested_fields\":false,\"prefix_indexed_fields\":[],\"resources_conns\":[\"*localhost\"],\"stats_conns\":[\"*localhost\"],\"suffix_indexed_fields\":[]}}"
|
||||
expectedGet := `{"attributes":{"accounts_conns":["*localhost"],"default_opts":{"*processRuns":1},"enabled":true,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"profile_runs":0,"resources_conns":["*localhost"],"stats_conns":["*localhost"],"suffix_indexed_fields":[]}}`
|
||||
if err != nil {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedGet, replyGet) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expectedGet, replyGet)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expectedGet, replyGet)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,6 +243,6 @@ func TestConfigStoreCfgInDBErr(t *testing.T) {
|
||||
err := rlcCfg.StoreCfgInDB(context.Background(), args, &reply)
|
||||
expected := "no DB connection for config"
|
||||
if err == nil || err.Error() != expected {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ type AttributeSCfg struct {
|
||||
PrefixIndexedFields *[]string
|
||||
SuffixIndexedFields *[]string
|
||||
NestedFields bool
|
||||
ProfileRuns int
|
||||
DefaultOpts map[string]interface{}
|
||||
}
|
||||
|
||||
@@ -62,6 +63,9 @@ func (alS *AttributeSCfg) loadFromJSONCfg(jsnCfg *AttributeSJsonCfg) (err error)
|
||||
if jsnCfg.Suffix_indexed_fields != nil {
|
||||
alS.SuffixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Suffix_indexed_fields))
|
||||
}
|
||||
if jsnCfg.Profile_runs != nil {
|
||||
alS.ProfileRuns = *jsnCfg.Profile_runs
|
||||
}
|
||||
if jsnCfg.Nested_fields != nil {
|
||||
alS.NestedFields = *jsnCfg.Nested_fields
|
||||
}
|
||||
@@ -76,6 +80,7 @@ func (alS *AttributeSCfg) AsMapInterface() (initialMP map[string]interface{}) {
|
||||
initialMP = map[string]interface{}{
|
||||
utils.EnabledCfg: alS.Enabled,
|
||||
utils.IndexedSelectsCfg: alS.IndexedSelects,
|
||||
utils.ProfileRunsCfg: alS.ProfileRuns,
|
||||
utils.NestedFieldsCfg: alS.NestedFields,
|
||||
utils.DefaultOptsCfg: alS.DefaultOpts,
|
||||
}
|
||||
@@ -108,6 +113,7 @@ func (alS AttributeSCfg) Clone() (cln *AttributeSCfg) {
|
||||
IndexedSelects: alS.IndexedSelects,
|
||||
NestedFields: alS.NestedFields,
|
||||
DefaultOpts: alS.DefaultOpts,
|
||||
ProfileRuns: alS.ProfileRuns,
|
||||
}
|
||||
if alS.ResourceSConns != nil {
|
||||
cln.ResourceSConns = utils.CloneStringSlice(alS.ResourceSConns)
|
||||
@@ -143,6 +149,7 @@ type AttributeSJsonCfg struct {
|
||||
Suffix_indexed_fields *[]string
|
||||
Nested_fields *bool // applies when indexed fields is not defined
|
||||
Default_opts map[string]interface{}
|
||||
Profile_runs *int
|
||||
}
|
||||
|
||||
func diffAttributeSJsonCfg(d *AttributeSJsonCfg, v1, v2 *AttributeSCfg) *AttributeSJsonCfg {
|
||||
|
||||
@@ -79,6 +79,7 @@ func TestAttributeSCfgAsMapInterface(t *testing.T) {
|
||||
utils.AccountSConnsCfg: []string{utils.MetaInternal},
|
||||
utils.StringIndexedFieldsCfg: []string{"*req.index1"},
|
||||
utils.PrefixIndexedFieldsCfg: []string{"*req.index1", "*req.index2"},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
utils.IndexedSelectsCfg: true,
|
||||
utils.NestedFieldsCfg: false,
|
||||
utils.SuffixIndexedFieldsCfg: []string{},
|
||||
@@ -116,6 +117,7 @@ func TestAttributeSCfgAsMapInterface2(t *testing.T) {
|
||||
utils.DefaultOptsCfg: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(7),
|
||||
},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
t.Error(err)
|
||||
@@ -142,6 +144,7 @@ func TestAttributeSCfgAsMapInterface3(t *testing.T) {
|
||||
utils.DefaultOptsCfg: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(1),
|
||||
},
|
||||
utils.ProfileRunsCfg: 0,
|
||||
}
|
||||
if conv, err := NewCGRConfigFromJSONStringWithDefaults(myJSONStr); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -670,6 +670,7 @@ const CGRATES_CFG_JSON = `
|
||||
"default_opts":{ //
|
||||
"*processRuns": 1, // number of run loops when processing event
|
||||
},
|
||||
"profile_runs": 0, // number of run a profile will process the event
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -756,6 +756,7 @@ func TestDfAttributeServJsonCfg(t *testing.T) {
|
||||
Default_opts: map[string]interface{}{
|
||||
utils.OptsAttributesProcessRuns: float64(1),
|
||||
},
|
||||
Profile_runs: utils.IntPointer(0),
|
||||
}
|
||||
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -649,6 +649,7 @@
|
||||
// "default_opts":{ //
|
||||
// "*processRuns": 1, // number of run loops when processing event
|
||||
// },
|
||||
// "profile_runs": 0, // number of run a profile will process the event
|
||||
// },
|
||||
|
||||
|
||||
@@ -816,7 +817,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": "Sorting", "path": "Sorting", "type": "*variable", "value": "~*req.4"},
|
||||
// {"tag": "SortingParameters", "path": "SortingParameters", "type": "*variable", "value": "~*req.5"},
|
||||
// {"tag": "RouteID", "path": "RouteID", "type": "*variable", "value": "~*req.6"},
|
||||
@@ -825,7 +826,7 @@
|
||||
// {"tag": "RouteRateProfileIDs", "path": "RouteRateProfileIDs", "type": "*variable", "value": "~*req.9"},
|
||||
// {"tag": "RouteResourceIDs", "path": "RouteResourceIDs", "type": "*variable", "value": "~*req.10"},
|
||||
// {"tag": "RouteStatIDs", "path": "RouteStatIDs", "type": "*variable", "value": "~*req.11"},
|
||||
// {"tag": "RouteWeight", "path": "RouteWeight", "type": "*variable", "value": "~*req.12"},
|
||||
// {"tag": "RouteWeights", "path": "RouteWeights", "type": "*variable", "value": "~*req.12"},
|
||||
// {"tag": "RouteBlocker", "path": "RouteBlocker", "type": "*variable", "value": "~*req.13"},
|
||||
// {"tag": "RouteParameters", "path": "RouteParameters", "type": "*variable", "value": "~*req.14"},
|
||||
// ],
|
||||
|
||||
@@ -56,7 +56,7 @@ func (alS *AttributeService) Shutdown() {
|
||||
|
||||
// attributeProfileForEvent returns the matching attribute
|
||||
func (alS *AttributeService) attributeProfileForEvent(ctx *context.Context, tnt string, attrsIDs []string,
|
||||
evNm utils.MapStorage, lastID string) (matchAttrPrfl *AttributeProfile, err error) {
|
||||
evNm utils.MapStorage, lastID string, processedPrfNo map[string]int, profileRuns int) (matchAttrPrfl *AttributeProfile, err error) {
|
||||
var attrIDs []string
|
||||
if len(attrsIDs) != 0 {
|
||||
attrIDs = attrsIDs
|
||||
@@ -82,7 +82,8 @@ func (alS *AttributeService) attributeProfileForEvent(ctx *context.Context, tnt
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
(evNm[utils.MetaVars].(utils.MapStorage))[utils.MetaAttrPrfTenantID] = aPrfl.TenantIDInline()
|
||||
tntID := aPrfl.TenantIDInline()
|
||||
(evNm[utils.MetaVars].(utils.MapStorage))[utils.MetaAttrPrfTenantID] = tntID
|
||||
if pass, err := alS.filterS.Pass(ctx, tnt, aPrfl.FilterIDs,
|
||||
evNm); err != nil {
|
||||
return nil, err
|
||||
@@ -90,7 +91,8 @@ func (alS *AttributeService) attributeProfileForEvent(ctx *context.Context, tnt
|
||||
continue
|
||||
}
|
||||
if (matchAttrPrfl == nil || matchAttrPrfl.Weight < aPrfl.Weight) &&
|
||||
aPrfl.TenantIDInline() != lastID {
|
||||
tntID != lastID &&
|
||||
(profileRuns <= 0 || processedPrfNo[tntID] < profileRuns) {
|
||||
matchAttrPrfl = aPrfl
|
||||
}
|
||||
}
|
||||
@@ -163,10 +165,10 @@ func (attr *AttrArgsProcessEvent) Clone() *AttrArgsProcessEvent {
|
||||
}
|
||||
|
||||
// processEvent will match event with attribute profile and do the necessary replacements
|
||||
func (alS *AttributeService) processEvent(ctx *context.Context, tnt string, args *AttrArgsProcessEvent, evNm utils.MapStorage, dynDP utils.DataProvider, lastID string) (
|
||||
rply *AttrSProcessEventReply, err error) {
|
||||
func (alS *AttributeService) processEvent(ctx *context.Context, tnt string, args *AttrArgsProcessEvent, evNm utils.MapStorage, dynDP utils.DataProvider,
|
||||
lastID string, processedPrfNo map[string]int, profileRuns int) (rply *AttrSProcessEventReply, err error) {
|
||||
var attrPrf *AttributeProfile
|
||||
if attrPrf, err = alS.attributeProfileForEvent(ctx, tnt, args.AttributeIDs, evNm, lastID); err != nil {
|
||||
if attrPrf, err = alS.attributeProfileForEvent(ctx, tnt, args.AttributeIDs, evNm, lastID, processedPrfNo, profileRuns); err != nil {
|
||||
return
|
||||
}
|
||||
rply = &AttrSProcessEventReply{
|
||||
@@ -241,7 +243,7 @@ func (alS *AttributeService) V1GetAttributeForEvent(ctx *context.Context, args *
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString)
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
err = utils.NewErrServerError(err)
|
||||
@@ -272,8 +274,17 @@ func (alS *AttributeService) V1ProcessEvent(ctx *context.Context, args *AttrArgs
|
||||
return
|
||||
}
|
||||
|
||||
profileRuns := alS.cgrcfg.AttributeSCfg().ProfileRuns
|
||||
if opt, has := args.APIOpts[utils.OptsAttributesProfileRuns]; has {
|
||||
var val int64
|
||||
if val, err = utils.IfaceAsTInt64(opt); err != nil {
|
||||
return
|
||||
}
|
||||
profileRuns = int(val)
|
||||
}
|
||||
args.CGREvent = args.CGREvent.Clone()
|
||||
processedPrf := make(utils.StringSet)
|
||||
processedPrfNo := make(map[string]int)
|
||||
eNV := utils.MapStorage{
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
@@ -296,7 +307,7 @@ func (alS *AttributeService) V1ProcessEvent(ctx *context.Context, args *AttrArgs
|
||||
for i := int64(0); i < processRuns; i++ {
|
||||
(eNV[utils.MetaVars].(utils.MapStorage))[utils.OptsAttributesProcessRuns] = i + 1
|
||||
var evRply *AttrSProcessEventReply
|
||||
evRply, err = alS.processEvent(ctx, tnt, args, eNV, dynDP, lastID)
|
||||
evRply, err = alS.processEvent(ctx, tnt, args, eNV, dynDP, lastID, processedPrfNo, profileRuns)
|
||||
if err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
err = utils.NewErrServerError(err)
|
||||
@@ -310,6 +321,7 @@ func (alS *AttributeService) V1ProcessEvent(ctx *context.Context, args *AttrArgs
|
||||
lastID = evRply.MatchedProfiles[0]
|
||||
matchedIDs = append(matchedIDs, lastID)
|
||||
processedPrf.Add(lastID)
|
||||
processedPrfNo[lastID] = processedPrfNo[lastID] + 1
|
||||
for _, fldName := range evRply.AlteredFields {
|
||||
alteredFields.Add(fldName)
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ func TestAttributesattributeProfileForEventNoDBConn(t *testing.T) {
|
||||
lastID := ""
|
||||
alS.dm = nil
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID); err == nil || err != utils.ErrNoDatabaseConn {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrNoDatabaseConn {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNoDatabaseConn, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
@@ -478,7 +478,7 @@ func TestAttributesattributeProfileForEventErrNotFound(t *testing.T) {
|
||||
}
|
||||
lastID := ""
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID); err == nil || err != utils.ErrNotFound {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrNotFound {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
@@ -537,7 +537,7 @@ func TestAttributesattributeProfileForEventErrPass(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{},
|
||||
}
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_1"}, evNm, lastID); err == nil || err != utils.ErrWrongPath {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_1"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrWrongPath {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrWrongPath, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
|
||||
@@ -233,7 +233,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString)
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -247,7 +247,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString)
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -262,7 +262,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString)
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -285,7 +285,7 @@ func TestAttributeProcessEvent(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[0], eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[0], eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -304,7 +304,7 @@ func TestAttributeProcessEventWithNotFound(t *testing.T) {
|
||||
},
|
||||
}
|
||||
if _, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[3], eNM,
|
||||
newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString); err == nil || err != utils.ErrNotFound {
|
||||
newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err == nil || err != utils.ErrNotFound {
|
||||
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
|
||||
}
|
||||
}
|
||||
@@ -324,7 +324,7 @@ func TestAttributeProcessEventWithIDs(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
if atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[3], eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString); err != nil {
|
||||
if atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[3], eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err != nil {
|
||||
} else if !reflect.DeepEqual(eRply, atrp) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(atrp))
|
||||
}
|
||||
@@ -1837,7 +1837,7 @@ func TestProcessAttributeConstant(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -1896,7 +1896,7 @@ func TestProcessAttributeVariable(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -1962,7 +1962,7 @@ func TestProcessAttributeComposed(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2023,7 +2023,7 @@ func TestProcessAttributeUsageDifference(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2084,7 +2084,7 @@ func TestProcessAttributeSum(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2145,7 +2145,7 @@ func TestProcessAttributeDiff(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2206,7 +2206,7 @@ func TestProcessAttributeMultiply(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2267,7 +2267,7 @@ func TestProcessAttributeDivide(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2328,7 +2328,7 @@ func TestProcessAttributeValueExponent(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2389,7 +2389,7 @@ func TestProcessAttributeUnixTimeStamp(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2449,7 +2449,7 @@ func TestProcessAttributePrefix(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2509,7 +2509,7 @@ func TestProcessAttributeSuffix(t *testing.T) {
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString)
|
||||
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, newDynamicDP(context.TODO(), nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -2979,3 +2979,124 @@ func TestAttributesPorcessEventMatchingProcessRuns(t *testing.T) {
|
||||
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expReply), utils.ToJSON(reply))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttributeMultipleProfileRunns(t *testing.T) {
|
||||
cfg := config.NewDefaultCGRConfig()
|
||||
cfg.AttributeSCfg().IndexedSelects = false
|
||||
dm := NewDataManager(NewInternalDB(nil, nil, true), cfg.CacheCfg(), nil)
|
||||
Cache.Clear(nil)
|
||||
attrS = NewAttributeService(dm, &FilterS{dm: dm, cfg: cfg}, cfg)
|
||||
attrPrf1Exists := &AttributeProfile{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: "ATTR_1",
|
||||
FilterIDs: []string{},
|
||||
Attributes: []*Attribute{{
|
||||
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
||||
Value: config.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
||||
}},
|
||||
Weight: 10,
|
||||
}
|
||||
attrPrf2Exists := &AttributeProfile{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: "ATTR_2",
|
||||
FilterIDs: []string{},
|
||||
Attributes: []*Attribute{{
|
||||
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
||||
Value: config.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
||||
}},
|
||||
Weight: 5,
|
||||
}
|
||||
// Add attribute in DM
|
||||
if err := dm.SetAttributeProfile(context.TODO(), attrPrf1Exists, true); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err = dm.SetAttributeProfile(context.TODO(), attrPrf2Exists, true); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
// Add attribute in DM
|
||||
if _, err := dm.GetAttributeProfile(context.TODO(), attrPrf1Exists.Tenant, attrPrf1Exists.ID, true, false, utils.NonTransactional); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := dm.GetAttributeProfile(context.TODO(), attrPrf2Exists.Tenant, attrPrf2Exists.ID, true, false, utils.NonTransactional); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
args := &AttrArgsProcessEvent{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
},
|
||||
APIOpts: map[string]interface{}{
|
||||
utils.OptsAttributesProfileRuns: 2,
|
||||
utils.OptsAttributesProcessRuns: 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
eRply := AttrSProcessEventReply{
|
||||
MatchedProfiles: []string{"cgrates.org:ATTR_1", "cgrates.org:ATTR_2", "cgrates.org:ATTR_1", "cgrates.org:ATTR_2"},
|
||||
AlteredFields: []string{utils.MetaReq + utils.NestingSep + "Field1",
|
||||
utils.MetaReq + utils.NestingSep + "Field2"},
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: args.CGREvent.ID,
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
"Field1": "Value1",
|
||||
"Field2": "Value2",
|
||||
},
|
||||
APIOpts: map[string]interface{}{
|
||||
utils.OptsAttributesProfileRuns: 2,
|
||||
utils.OptsAttributesProcessRuns: 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
var reply AttrSProcessEventReply
|
||||
if err := attrS.V1ProcessEvent(context.TODO(), args, &reply); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
sort.Strings(reply.AlteredFields)
|
||||
if !reflect.DeepEqual(eRply, reply) {
|
||||
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(reply))
|
||||
}
|
||||
|
||||
args = &AttrArgsProcessEvent{
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
},
|
||||
APIOpts: map[string]interface{}{
|
||||
utils.OptsAttributesProfileRuns: 1,
|
||||
utils.OptsAttributesProcessRuns: 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
eRply = AttrSProcessEventReply{
|
||||
MatchedProfiles: []string{"cgrates.org:ATTR_1", "cgrates.org:ATTR_2"},
|
||||
AlteredFields: []string{utils.MetaReq + utils.NestingSep + "Field1",
|
||||
utils.MetaReq + utils.NestingSep + "Field2"},
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: cfg.GeneralCfg().DefaultTenant,
|
||||
ID: args.CGREvent.ID,
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
"Field1": "Value1",
|
||||
"Field2": "Value2",
|
||||
},
|
||||
APIOpts: map[string]interface{}{
|
||||
utils.OptsAttributesProfileRuns: 1,
|
||||
utils.OptsAttributesProcessRuns: 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
reply = AttrSProcessEventReply{}
|
||||
if err := attrS.V1ProcessEvent(context.TODO(), args, &reply); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
sort.Strings(reply.AlteredFields)
|
||||
if !reflect.DeepEqual(eRply, reply) {
|
||||
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(reply))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ cgrates (1.0) UNRELEASED; urgency=medium
|
||||
* [RSRParsers] Added *slice dataconverter
|
||||
* [CacheS] Updated LoadCache and ReloadCache APIs
|
||||
* [EEs] Added *log exporter
|
||||
* [AttributeS] Added profile_runs to control how many times a profile is proccessed for an event
|
||||
|
||||
-- DanB <danb@cgrates.org> Thu, 4 May 2021 12:05:00 +0200
|
||||
|
||||
|
||||
@@ -1874,6 +1874,7 @@ const (
|
||||
// AttributeSCfg
|
||||
IndexedSelectsCfg = "indexed_selects"
|
||||
ProcessRunsCfg = "process_runs"
|
||||
ProfileRunsCfg = "profile_runs"
|
||||
NestedFieldsCfg = "nested_fields"
|
||||
|
||||
// ChargerSCfg
|
||||
@@ -2087,7 +2088,7 @@ var CGROptionsSet = NewStringSet([]string{OptsRatesStartTime, OptsRatesUsage, Op
|
||||
OptsSesDebitInterval, OptsStirATest, OptsStirPayloadMaxDuration, OptsStirIdentity,
|
||||
OptsStirOriginatorTn, OptsStirOriginatorURI, OptsStirDestinationTn, OptsStirDestinationURI,
|
||||
OptsStirPublicKeyPath, OptsStirPrivateKeyPath, OptsAPIKey, OptsRouteID, OptsContext,
|
||||
OptsAttributesProcessRuns, OptsRoutesLimit, OptsRoutesOffset, OptsSesChargeable,
|
||||
OptsAttributesProcessRuns, OptsAttributesProfileRuns, OptsRoutesLimit, OptsRoutesOffset, OptsSesChargeable,
|
||||
RemoteHostOpt, CacheOpt, OptsRoutesProfilesCount, OptsDispatchersProfilesCount,
|
||||
OptsSesAttributeS, OptsSesAttributeIDs, OptsSesAttributeSDerivedReply, OptsSesBlockerError,
|
||||
OptsSesCDRs, OptsSesCDRsDerivedReply, OptsSesChargerS, OptsSesResourceS, OptsSesResourceSAuthorize,
|
||||
@@ -2179,6 +2180,7 @@ const (
|
||||
Subsys = "*subsys"
|
||||
MetaMethod = "*reqMethod"
|
||||
OptsAttributesProcessRuns = "*processRuns"
|
||||
OptsAttributesProfileRuns = "*profileRuns"
|
||||
MetaEventType = "*eventType"
|
||||
EventType = "EventType"
|
||||
SchedulerInit = "SchedulerInit"
|
||||
|
||||
Reference in New Issue
Block a user