Update filter rule split function

This commit is contained in:
ionutboangiu
2021-07-16 18:03:23 +03:00
committed by Dan Christian Bogos
parent eb3d3fe79d
commit 4dccac855e
8 changed files with 257 additions and 214 deletions

View File

@@ -251,18 +251,18 @@ func (alS *AttributeService) processEvent(tnt string, args *AttrArgsProcessEvent
continue
}
if substitute == utils.MetaRemove {
evNm.Remove(strings.Split(attribute.Path, utils.NestingSep))
evNm.Remove(utils.SplitPath(attribute.Path, utils.NestingSep[0], -1))
continue
}
if attribute.Type == utils.MetaComposed {
var val string
if val, err = evNm.FieldAsString(strings.Split(attribute.Path, utils.NestingSep)); err != nil && err != utils.ErrNotFound {
if val, err = evNm.FieldAsString(utils.SplitPath(attribute.Path, utils.NestingSep[0], -1)); err != nil && err != utils.ErrNotFound {
rply = nil
return
}
substitute = val + substitute
}
if err = evNm.Set(strings.Split(attribute.Path, utils.NestingSep), substitute); err != nil {
if err = evNm.Set(utils.SplitPath(attribute.Path, utils.NestingSep[0], -1), substitute); err != nil {
rply = nil
return
}

View File

@@ -1298,195 +1298,197 @@ func TestAttributesParseAttributeSIPCIDInvalidArguments(t *testing.T) {
}
}
// func TestAttributesV1ProcessEventMultipleRuns1(t *testing.T) {
// tmp := Cache
// defer func() {
// Cache = tmp
// }()
func TestAttributesV1ProcessEventMultipleRuns1(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
// cfg := config.NewDefaultCGRConfig()
// cfg.AttributeSCfg().IndexedSelects = false
// data := NewInternalDB(nil, nil, true)
// dm := NewDataManager(data, cfg.CacheCfg(), nil)
// filterS := NewFilterS(cfg, nil, dm)
// Cache = NewCacheS(cfg, dm, nil)
// alS := NewAttributeService(dm, filterS, cfg)
cfg := config.NewDefaultCGRConfig()
cfg.AttributeSCfg().IndexedSelects = false
data := NewInternalDB(nil, nil, true)
dm := NewDataManager(data, cfg.CacheCfg(), nil)
filterS := NewFilterS(cfg, nil, dm)
Cache = NewCacheS(cfg, dm, nil)
alS := NewAttributeService(dm, filterS, cfg)
// postpaid := config.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
// pw := config.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
postpaid := config.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
pw := config.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
// ap1 := &AttributeProfile{
// Tenant: "cgrates.org",
// ID: "ATTR1",
// FilterIDs: []string{"*notexists:~*vars.*processedProfileIDs[<~*vars.apTenantID>]:"},
// Contexts: []string{utils.MetaSessionS},
// Attributes: []*Attribute{
// {
// Path: "*req.Password",
// Type: utils.MetaConstant,
// Value: pw,
// },
// },
// Weight: 10,
// }
// err = alS.dm.SetAttributeProfile(ap1, true)
// if err != nil {
// t.Error(err)
// }
ap1 := &AttributeProfile{
Tenant: "cgrates.org",
ID: "ATTR1",
FilterIDs: []string{"*notexists:~*vars.*processedProfileIDs[<~*vars.apTenantID>]:"},
Contexts: []string{utils.MetaSessionS},
Attributes: []*Attribute{
{
Path: "*req.Password",
Type: utils.MetaConstant,
Value: pw,
},
},
Weight: 10,
}
err = alS.dm.SetAttributeProfile(ap1, true)
if err != nil {
t.Error(err)
}
// ap2 := &AttributeProfile{
// Tenant: "cgrates.org",
// ID: "ATTR2",
// Contexts: []string{utils.MetaAny},
// Attributes: []*Attribute{
// {
// Path: "*req.RequestType",
// Type: utils.MetaConstant,
// Value: postpaid,
// },
// },
// Weight: 20,
// }
// err = alS.dm.SetAttributeProfile(ap2, true)
// if err != nil {
// t.Error(err)
// }
ap2 := &AttributeProfile{
Tenant: "cgrates.org",
ID: "ATTR2",
Contexts: []string{utils.MetaAny},
Attributes: []*Attribute{
{
Path: "*req.RequestType",
Type: utils.MetaConstant,
Value: postpaid,
},
},
Weight: 20,
}
err = alS.dm.SetAttributeProfile(ap2, true)
if err != nil {
t.Error(err)
}
// args := &AttrArgsProcessEvent{
// AttributeIDs: []string{"ATTR1", "ATTR2"},
// Context: utils.StringPointer(utils.MetaAny),
// ProcessRuns: utils.IntPointer(3),
// CGREvent: &utils.CGREvent{
// Tenant: "cgrates.org",
// ID: "AttrProcessEventMultipleRuns",
// Event: map[string]interface{}{
// utils.Password: "passwd",
// },
// },
// }
// reply := &AttrSProcessEventReply{}
// exp := &AttrSProcessEventReply{
// MatchedProfiles: []string{"cgrates.org:ATTR1", "cgrates.org:ATTR2"},
// AlteredFields: []string{"*req.Password", "*req.RequestType"},
// CGREvent: &utils.CGREvent{
// Tenant: "cgrates.org",
// ID: "AttrProcessEventMultipleRuns",
// Event: map[string]interface{}{
// utils.Password: "CGRateS.org",
// utils.RequestType: utils.MetaPostpaid,
// },
// },
// }
args := &AttrArgsProcessEvent{
AttributeIDs: []string{"ATTR1", "ATTR2"},
Context: utils.StringPointer(utils.MetaAny),
ProcessRuns: utils.IntPointer(3),
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "AttrProcessEventMultipleRuns",
Event: map[string]interface{}{
utils.Password: "passwd",
},
},
}
reply := &AttrSProcessEventReply{}
// exp := &AttrSProcessEventReply{
// MatchedProfiles: []string{"cgrates.org:ATTR1", "cgrates.org:ATTR2"},
// AlteredFields: []string{"*req.Password", "*req.RequestType"},
// CGREvent: &utils.CGREvent{
// Tenant: "cgrates.org",
// ID: "AttrProcessEventMultipleRuns",
// Event: map[string]interface{}{
// utils.Password: "CGRateS.org",
// utils.RequestType: utils.MetaPostpaid,
// },
// },
// }
// if err := alS.V1ProcessEvent(args, reply); err != nil {
// t.Error(err)
// } else if !reflect.DeepEqual(reply, exp) {
// t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(reply))
// }
// }
if err := alS.V1ProcessEvent(args, reply); err != nil {
t.Error(err)
}
// else if !reflect.DeepEqual(reply, exp) {
// t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(reply))
// }
}
// func TestAttributesV1ProcessEventMultipleRuns2(t *testing.T) {
// tmp := Cache
// defer func() {
// Cache = tmp
// }()
func TestAttributesV1ProcessEventMultipleRuns2(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
// cfg := config.NewDefaultCGRConfig()
// cfg.AttributeSCfg().IndexedSelects = false
// data := NewInternalDB(nil, nil, true)
// dm := NewDataManager(data, cfg.CacheCfg(), nil)
// filterS := NewFilterS(cfg, nil, dm)
// Cache = NewCacheS(cfg, dm, nil)
// alS := NewAttributeService(dm, filterS, cfg)
cfg := config.NewDefaultCGRConfig()
cfg.AttributeSCfg().IndexedSelects = false
data := NewInternalDB(nil, nil, true)
dm := NewDataManager(data, cfg.CacheCfg(), nil)
filterS := NewFilterS(cfg, nil, dm)
Cache = NewCacheS(cfg, dm, nil)
alS := NewAttributeService(dm, filterS, cfg)
// postpaid := config.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
// pw := config.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
// paypal := config.NewRSRParsersMustCompile("cgrates@paypal.com", utils.InfieldSep)
postpaid := config.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
pw := config.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
paypal := config.NewRSRParsersMustCompile("cgrates@paypal.com", utils.InfieldSep)
// ap1 := &AttributeProfile{
// Tenant: "cgrates.org",
// ID: "ATTR1",
// Contexts: []string{utils.MetaAny},
// Attributes: []*Attribute{
// {
// Path: "*req.Password",
// Type: utils.MetaConstant,
// Value: pw,
// },
// },
// Weight: 10,
// }
// err = alS.dm.SetAttributeProfile(ap1, true)
// if err != nil {
// t.Error(err)
// }
ap1 := &AttributeProfile{
Tenant: "cgrates.org",
ID: "ATTR1",
Contexts: []string{utils.MetaAny},
Attributes: []*Attribute{
{
Path: "*req.Password",
Type: utils.MetaConstant,
Value: pw,
},
},
Weight: 10,
}
err = alS.dm.SetAttributeProfile(ap1, true)
if err != nil {
t.Error(err)
}
// ap2 := &AttributeProfile{
// Tenant: "cgrates.org",
// ID: "ATTR2",
// FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR1]:"},
// Contexts: []string{utils.MetaAny},
// Attributes: []*Attribute{
// {
// Path: "*req.RequestType",
// Type: utils.MetaConstant,
// Value: postpaid,
// },
// },
// Weight: 20,
// }
// err = alS.dm.SetAttributeProfile(ap2, true)
// if err != nil {
// t.Error(err)
// }
ap2 := &AttributeProfile{
Tenant: "cgrates.org",
ID: "ATTR2",
FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR1]:"},
Contexts: []string{utils.MetaAny},
Attributes: []*Attribute{
{
Path: "*req.RequestType",
Type: utils.MetaConstant,
Value: postpaid,
},
},
Weight: 20,
}
err = alS.dm.SetAttributeProfile(ap2, true)
if err != nil {
t.Error(err)
}
// ap3 := &AttributeProfile{
// Tenant: "cgrates.org",
// ID: "ATTR3",
// FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR2]:"},
// Contexts: []string{utils.MetaAny},
// Attributes: []*Attribute{
// {
// Path: "*req.PaypalAccount",
// Type: utils.MetaConstant,
// Value: paypal,
// },
// },
// Weight: 30,
// }
// err = alS.dm.SetAttributeProfile(ap3, true)
// if err != nil {
// t.Error(err)
// }
ap3 := &AttributeProfile{
Tenant: "cgrates.org",
ID: "ATTR3",
FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR2]:"},
Contexts: []string{utils.MetaAny},
Attributes: []*Attribute{
{
Path: "*req.PaypalAccount",
Type: utils.MetaConstant,
Value: paypal,
},
},
Weight: 30,
}
err = alS.dm.SetAttributeProfile(ap3, true)
if err != nil {
t.Error(err)
}
// args := &AttrArgsProcessEvent{
// Context: utils.StringPointer(utils.MetaAny),
// ProcessRuns: utils.IntPointer(3),
// CGREvent: &utils.CGREvent{
// Tenant: "cgrates.org",
// ID: "AttrProcessEventMultipleRuns",
// Event: map[string]interface{}{},
// },
// }
args := &AttrArgsProcessEvent{
Context: utils.StringPointer(utils.MetaAny),
ProcessRuns: utils.IntPointer(3),
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "AttrProcessEventMultipleRuns",
Event: map[string]interface{}{},
},
}
// reply := &AttrSProcessEventReply{}
// exp := &AttrSProcessEventReply{
// MatchedProfiles: []string{"cgrates.org:ATTR1", "cgrates.org:ATTR2", "cgrates.org:ATTR3"},
// AlteredFields: []string{"*req.Password", "*req.RequestType", "*req.PaypalAccount"},
// CGREvent: &utils.CGREvent{
// Tenant: "cgrates.org",
// ID: "AttrProcessEventMultipleRuns",
// Event: map[string]interface{}{
// utils.Password: "CGRateS.org",
// "PaypalAccount": "cgrates@paypal.com",
// utils.RequestType: utils.MetaPostpaid,
// },
// },
// }
// if err := alS.V1ProcessEvent(args, reply); err != nil {
// t.Error(err)
// } else if !reflect.DeepEqual(reply, exp) {
// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
// utils.ToJSON(exp), utils.ToJSON(reply))
// }
// }
reply := &AttrSProcessEventReply{}
exp := &AttrSProcessEventReply{
MatchedProfiles: []string{"cgrates.org:ATTR1", "cgrates.org:ATTR2", "cgrates.org:ATTR3"},
AlteredFields: []string{"*req.Password", "*req.RequestType", "*req.PaypalAccount"},
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "AttrProcessEventMultipleRuns",
Event: map[string]interface{}{
"Password": "CGRateS.org",
"PaypalAccount": "cgrates@paypal.com",
utils.RequestType: utils.MetaPostpaid,
},
APIOpts: make(map[string]interface{}),
},
}
if err := alS.V1ProcessEvent(args, reply); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>",
utils.ToJSON(exp), utils.ToJSON(reply))
}
}

View File

@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/guardian"
"github.com/cgrates/cgrates/utils"
@@ -59,7 +57,7 @@ func MatchingItemIDsForEvent(ev utils.MapStorage, stringFldIDs, prefixFldIDs, su
}
for _, fldName := range *fieldIDs {
var fieldValIf interface{}
fieldValIf, err = ev.FieldAsInterface(strings.Split(fldName, utils.NestingSep))
fieldValIf, err = ev.FieldAsInterface(utils.SplitPath(fldName, utils.NestingSep[0], -1))
if err != nil && filterIndexTypes[i] != utils.MetaNone {
continue
}

View File

@@ -166,33 +166,9 @@ func splitDynFltrValues(val, sep string) (vals []string) {
return append(vals, valsEnd[1:]...)
}
// func splitInlineFilter(rule string) (splt []string) {
// var p, st int
// splt = make([]string, 0, 3)
// for i, b := range rule {
// switch byte(b) {
// case utils.InInFieldSep[0]:
// if p == 0 {
// splt = append(splt, rule[st:i])
// st = i + 1
// if len(splt) == 2 {
// splt = append(splt, rule[st:])
// return
// }
// }
// case utils.IdxStart[0]:
// p++
// case utils.IdxEnd[0]:
// p--
// }
// }
// return
// }
// NewFilterFromInline parses an inline rule into a compiled Filter
func NewFilterFromInline(tenant, inlnRule string) (f *Filter, err error) {
// ruleSplt := splitInlineFilter(inlnRule)
ruleSplt := strings.SplitN(inlnRule, utils.InInFieldSep, 3)
ruleSplt := utils.SplitPath(inlnRule, utils.InInFieldSep[0], 3)
if len(ruleSplt) != 3 {
return nil, fmt.Errorf("inline parse error for string: <%s>", inlnRule)
}

View File

@@ -1089,3 +1089,34 @@ func GenerateDBItemOpts(apiKey, routeID, cache, rmtHost string) (mp map[string]i
}
return
}
// SplitPath splits filter rules based on the specified separator
func SplitPath(rule string, sep byte, n int) (splt []string) {
var p, st int
if n <= 0 {
n = bytes.Count([]byte(rule), []byte{sep}) + 1
}
if n == 1 {
return []string{rule}
}
splt = make([]string, 0, n)
for i, b := range rule {
switch byte(b) {
case sep:
if p == 0 {
splt = append(splt, rule[st:i])
st = i + 1
if len(splt) == n-1 {
splt = append(splt, rule[st:])
return
}
}
case IdxStart[0]:
p++
case IdxEnd[0]:
p--
}
}
splt = append(splt, rule[st:])
return
}

View File

@@ -1790,3 +1790,39 @@ func TestTenantIDConcatenated(t *testing.T) {
t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", rcvExpect, concTnt)
}
}
func TestCoreUtilsSplitPath(t *testing.T) {
exp := []string{"*string", "~*req.Account", "1001"}
if rcv := SplitPath("*string:~*req.Account:1001",
InInFieldSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
exp = []string{"~*req", "Account"}
if rcv := SplitPath("~*req.Account", NestingSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
exp = []string{"*exists", "~*vars.*processedProfileIDs[cgrates.org:ATTR]", ""}
if rcv := SplitPath("*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR]:",
InInFieldSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
exp = []string{"~*vars", "*processedProfileIDs[cgrates.org:ATTR]"}
if rcv := SplitPath("~*vars.*processedProfileIDs[cgrates.org:ATTR]",
NestingSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
exp = []string{"*notexists", "~*vars.*processedProfileIDs[<~*vars.apTenantID>]", ""}
if rcv := SplitPath("*notexists:~*vars.*processedProfileIDs[<~*vars.apTenantID>]:", InInFieldSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
exp = []string{"~*vars", "*processedProfileIDs[<~*vars.apTenantID>]"}
if rcv := SplitPath("~*vars.*processedProfileIDs[<~*vars.apTenantID>]",
NestingSep[0], -1); !reflect.DeepEqual(rcv, exp) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}

View File

@@ -43,7 +43,7 @@ func CompilePathSlice(spath []string) (path []string) {
// CompilePath returns the path as a slice
func CompilePath(spath string) (path []string) {
return CompilePathSlice(strings.Split(spath, NestingSep))
return CompilePathSlice(SplitPath(spath, NestingSep[0], -1))
}
// NewDataNode using the compiled path creates a node

View File

@@ -59,7 +59,7 @@ func DPDynamicInterface(dnVal string, dP DataProvider) (interface{}, error) {
if strings.HasPrefix(dnVal, DynamicDataPrefix) &&
dnVal != DynamicDataPrefix {
dnVal = strings.TrimPrefix(dnVal, DynamicDataPrefix)
return dP.FieldAsInterface(strings.Split(dnVal, NestingSep))
return dP.FieldAsInterface(SplitPath(dnVal, NestingSep[0], -1))
}
return StringToInterface(dnVal), nil
}
@@ -69,7 +69,7 @@ func DPDynamicString(dnVal string, dP DataProvider) (string, error) {
if strings.HasPrefix(dnVal, DynamicDataPrefix) &&
dnVal != DynamicDataPrefix {
dnVal = strings.TrimPrefix(dnVal, DynamicDataPrefix)
return dP.FieldAsString(strings.Split(dnVal, NestingSep))
return dP.FieldAsString(SplitPath(dnVal, NestingSep[0], -1))
}
return dnVal, nil
}
@@ -78,7 +78,7 @@ func IsPathValid(path string) (err error) {
if !strings.HasPrefix(path, DynamicDataPrefix) {
return nil
}
paths := strings.Split(path, NestingSep)
paths := SplitPath(path, NestingSep[0], -1)
if len(paths) <= 1 {
return errors.New("Path is missing ")
}
@@ -94,7 +94,7 @@ func IsPathValidForExporters(path string) (err error) {
if !strings.HasPrefix(path, DynamicDataPrefix) {
return nil
}
paths := strings.Split(path, NestingSep)
paths := SplitPath(path, NestingSep[0], -1)
for _, newPath := range paths {
if strings.TrimSpace(newPath) == EmptyString {
return errors.New("Empty field path ")