Added profile_runs in attributes

This commit is contained in:
Trial97
2021-09-07 16:26:57 +03:00
committed by Dan Christian Bogos
parent 7993a409a5
commit d3f58e311d
12 changed files with 208 additions and 56 deletions

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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))
}
}