Added tests for Dynamic RSRParsers

This commit is contained in:
Trial97
2020-07-14 14:04:31 +03:00
committed by Dan Christian Bogos
parent 69a012c05a
commit 715439475e
11 changed files with 303 additions and 57 deletions

View File

@@ -202,21 +202,6 @@ func (prsr *RSRParser) AttrName() string {
func (prsr *RSRParser) Compile() (err error) {
parserRules := prsr.Rules
if dynIdxStart := strings.IndexByte(parserRules, utils.RSRDynStartChar); dynIdxStart != -1 {
if dynIdxEnd := strings.IndexByte(parserRules[dynIdxStart:], utils.RSRDynEndChar); dynIdxEnd != -1 {
dynIdxEnd += dynIdxStart
sep := ";"
var dynrules RSRParsers
if dynrules, err = NewRSRParsers(parserRules[dynIdxStart+1:dynIdxEnd], sep); err != nil {
return
}
prsr.dynRules = dynrules
prsr.dynIdxStart = dynIdxStart
prsr.dynIdxEnd = dynIdxEnd + 1
return
}
}
if dynIdxStart := strings.IndexByte(parserRules, utils.RSRDynStartChar); dynIdxStart != -1 {
if dynIdxEnd := strings.IndexByte(parserRules[dynIdxStart:], utils.RSRDynEndChar); dynIdxEnd != -1 {
var dynrules RSRParsers

View File

@@ -412,6 +412,31 @@ func TestRSRParserDynamic2(t *testing.T) {
} else if out != "2.10" {
t.Errorf("Expected 2.10 received: %q", out)
}
dP = utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
},
}
if _, err := prsr.ParseDataProvider(dP); err != utils.ErrNotFound {
t.Errorf("Expected error %s, received: %v", utils.ErrNotFound, err)
}
prsr, err = NewRSRParsersFromSlice([]string{"2.", "~*req.CGRID<~*opts.Converter>"})
if err != nil {
t.Fatal(err)
}
dP = utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
},
utils.MetaOpts: utils.MapStorage{
"Converter": "{*",
},
}
if _, err := prsr.ParseDataProvider(dP); err == nil {
t.Error(err)
}
}
func TestRSRParserDynamic3(t *testing.T) {
@@ -437,19 +462,111 @@ func TestRSRParserDynamic3(t *testing.T) {
t.Errorf("Expected 2.10-MB received: %q", out)
}
// prsr, err = NewRSRParsers("2.{*};~*req.<~*req.CGRID;~*req.RunID;-Cos>t;-;~*req.<~*req.UnitField>", ";")
// expErr := "invalid converter value in string: <*>, err: unsupported converter definition: <*>"
// if err == nil || err.Error() != expErr {
// t.Fatal(err)
// }
// prsr, err = NewRSRParsers("2.;~*req.<~*req.CGRID;~*req.RunID;-Cos>t;-;~*req.Unit{*}", ";")
// if err == nil || err.Error() != expErr {
// t.Fatal(err)
// }
// prsr, err = NewRSRParsers("2.;~*req.<~*req.CGRID;~*req.RunID;-Cos>t;-;~*req.<~*req.UnitField{*}>", ";")
// if err == nil || err.Error() != expErr {
// t.Fatal(err)
// }
}
func TestRSRParserParseDataProviderWithInterfaces(t *testing.T) {
prsr, err := NewRSRParsersFromSlice([]string{"~*req.<~*req.CGRID;~*req.RunID;-Cos>t", "s"})
if err != nil {
t.Fatal(err)
}
dP := utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
utils.RunID: utils.MetaDefault,
"cgridUniq*default-Cost": 10,
},
}
if out, err := prsr.ParseDataProviderWithInterfaces(dP); err != nil {
t.Error(err)
} else if out != "10s" {
t.Errorf("Expected 10s received: %q", out)
}
prsr, err = NewRSRParsersFromSlice([]string{"2.", "~*req.<~*req.CGRID;~*req.RunID;-Cos>t", "s"})
if err != nil {
t.Fatal(err)
}
if out, err := prsr.ParseDataProviderWithInterfaces(dP); err != nil {
t.Error(err)
} else if out != "210s" {
t.Errorf("Expected 210s received: %q", out)
}
prsr, err = NewRSRParsersFromSlice([]string{"2.", "~*req.<~*req.CGRID;~*req.RunID;-Cost>"})
if err != nil {
t.Fatal(err)
}
if out, err := prsr.ParseDataProviderWithInterfaces(dP); err != nil {
t.Error(err)
} else if out != "210" {
t.Errorf("Expected 210 received: %q", out)
}
dP = utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
},
}
if _, err := prsr.ParseDataProviderWithInterfaces(dP); err != utils.ErrNotFound {
t.Errorf("Expected error %s, received: %v", utils.ErrNotFound, err)
}
prsr, err = NewRSRParsersFromSlice([]string{"2.", "~*req.CGRID<~*opts.Converter>"})
if err != nil {
t.Fatal(err)
}
dP = utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
},
utils.MetaOpts: utils.MapStorage{
"Converter": "{*",
},
}
if _, err := prsr.ParseDataProviderWithInterfaces(dP); err == nil {
t.Error(err)
}
}
func TestRSRParserCompileDynRule(t *testing.T) {
prsr, err := NewRSRParser("~*req.<~*req.CGRID;~*req.RunID;-Cos>t")
if err != nil {
t.Fatal(err)
}
dP := utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
utils.RunID: utils.MetaDefault,
"cgridUniq*default-Cost": 10,
},
}
if out, err := prsr.CompileDynRule(dP); err != nil {
t.Error(err)
} else if out != "~*req.cgridUniq*default-Cost" {
t.Errorf("Expected ~*req.cgridUniq*default-Cost received: %q", out)
}
dP = utils.MapStorage{
utils.MetaReq: utils.MapStorage{
utils.CGRID: "cgridUniq",
},
}
if _, err := prsr.CompileDynRule(dP); err != utils.ErrNotFound {
t.Errorf("Expected error %s, received: %v", utils.ErrNotFound, err)
}
prsr, err = NewRSRParser("~*req.CGRID")
if err != nil {
t.Fatal(err)
}
if out, err := prsr.CompileDynRule(dP); err != nil {
t.Error(err)
} else if out != "~*req.CGRID" {
t.Errorf("Expected ~*req.CGRID received: %q", out)
}
}

View File

@@ -305,11 +305,11 @@
"attempts": 1,
"filters": ["*string:~*req.ExporterUsed:RouteExporter"],
"fields":[
{"tag": "Cost", "path": "*uch[~*req.CGRID|~*req.RunID|-Cost]", "type": "*variable",
{"tag": "Cost", "path": "*uch<~*req.CGRID;~*req.RunID;-Cost>", "type": "*variable",
"value": "~*req.Cost", "rounding_decimals": 4},
{"tag": "Account", "path": "*uch[~*req.CGRID|~*req.RunID|-Account]", "type": "*variable", "value": "~*req.Account"},
{"tag": "RunID", "path": "*uch[~*req.CGRID|~*req.RunID|-RunID]", "type": "*variable", "value": "~*req.RunID"},
{"tag": "CustomVariable", "path": "*uch[~*req.CGRID|~*req.RunID|-CustomVariable]",
{"tag": "Account", "path": "*uch<~*req.CGRID;~*req.RunID;-Account>", "type": "*variable", "value": "~*req.Account"},
{"tag": "RunID", "path": "*uch<~*req.CGRID;~*req.RunID;-RunID>", "type": "*variable", "value": "~*req.RunID"},
{"tag": "CustomVariable", "path": "*uch<~*req.CGRID;~*req.RunID;-CustomVariable>",
"type": "*variable", "value": "CustomValue"}
],
},
@@ -330,12 +330,12 @@
{"tag": "Tenant", "path": "*exp.Tenant", "type": "*variable", "value": "~*req.Tenant"},
{"tag": "Account", "path": "*exp.Account", "type": "*variable", "value": "~*req.Account"},
{"tag": "Cost", "path": "*exp.Cost", "type": "*variable", "value": "~*req.Cost", "rounding_decimals": 4},
{"tag": "SupplierCustomVariable","filters": ["*exists:*uch[~*req.CGRID|~*req.RunID|-CustomVariable]:"],
"path": "*exp.SupplierCustomVariable", "type": "*variable", "value": "~*uch[~*req.CGRID|~*req.RunID|-CustomVariable]"},
{"tag": "SupplierCost","filters": ["*exists:*uch[~*req.CGRID|~*req.RunID|-Cost]:"],
"path": "*exp.SupplierCost", "type": "*variable", "value": "~*uch[~*req.CGRID|~*req.RunID|-Cost]"},
{"tag": "SupplierRun","filters": ["*exists:*uch[~*req.CGRID|~*req.RunID|-RunID]:"],
"path": "*exp.SupplierRun", "type": "*variable", "value": "~*uch[~*req.CGRID|~*req.RunID|-RunID]"},
{"tag": "SupplierCustomVariable","filters": ["*exists:*uch<~*req.CGRID;~*req.RunID;-CustomVariable>:"],
"path": "*exp.SupplierCustomVariable", "type": "*variable", "value": "~*uch<~*req.CGRID;~*req.RunID;-CustomVariable>"},
{"tag": "SupplierCost","filters": ["*exists:*uch<~*req.CGRID;~*req.RunID;-Cost>:"],
"path": "*exp.SupplierCost", "type": "*variable", "value": "~*uch<~*req.CGRID;~*req.RunID;-Cost>"},
{"tag": "SupplierRun","filters": ["*exists:*uch<~*req.CGRID;~*req.RunID;-RunID>:"],
"path": "*exp.SupplierRun", "type": "*variable", "value": "~*uch<~*req.CGRID;~*req.RunID;-RunID>"},
],
}
]

View File

@@ -69,7 +69,7 @@
"value":"`>`"},
{"tag": "X-Identity", "path": "*rep.X-Identity", "type": "*variable",
"value":"~*cgrep.STIRIdentity[~*cgrep.Routes.SortedRoutes[0].RouteID]"},
"value":"~*cgrep.STIRIdentity.<~*cgrep.Routes.SortedRoutes[0].RouteID>"},
]
},

View File

@@ -146,6 +146,24 @@ func (fS *FilterS) LazyPass(tenant string, filterIDs []string,
return
}
func splitDynFltrValues(val string) (vals []string) {
startIdx := strings.IndexByte(val, utils.RSRDynStartChar)
endIdx := strings.IndexByte(val, utils.RSRDynEndChar)
if startIdx == -1 || endIdx == -1 {
return strings.Split(val, utils.INFIELD_SEP)
}
vals = strings.Split(val[:startIdx], utils.INFIELD_SEP)
vals[len(vals)-1] += val[startIdx : endIdx+1]
val = val[endIdx+1:]
if len(val) == 0 {
return
}
valsEnd := splitDynFltrValues(val)
vals[len(vals)-1] += valsEnd[0]
return append(vals, valsEnd[1:]...)
}
// NewFilterFromInline parses an inline rule into a compiled Filter
func NewFilterFromInline(tenant, inlnRule string) (f *Filter, err error) {
ruleSplt := strings.SplitN(inlnRule, utils.InInFieldSep, 3)
@@ -154,7 +172,7 @@ func NewFilterFromInline(tenant, inlnRule string) (f *Filter, err error) {
}
var vals []string
if ruleSplt[2] != utils.EmptyString {
vals = strings.Split(ruleSplt[2], utils.INFIELD_SEP)
vals = splitDynFltrValues(ruleSplt[2])
}
f = &Filter{
Tenant: tenant,
@@ -267,6 +285,12 @@ func (fltr *FilterRule) CompileValues() (err error) {
} else if fltr.rsrElement == nil {
return fmt.Errorf("emtpy RSRParser in rule: <%s>", fltr.Element)
}
case utils.MetaExists, utils.MetaNotExists, utils.MetaEmpty, utils.MetaNotEmpty: // only the element is builded
if fltr.rsrElement, err = config.NewRSRParser(fltr.Element); err != nil {
return
} else if fltr.rsrElement == nil {
return fmt.Errorf("emtpy RSRParser in rule: <%s>", fltr.Element)
}
default:
if fltr.rsrValues, err = config.NewRSRParsersFromSlice(fltr.Values); err != nil {
return

View File

@@ -1329,3 +1329,33 @@ func TestPassPartial(t *testing.T) {
t.Errorf("Expecting: %+v, received: %+v", 0, len(ruleList))
}
}
func TestNewFilterFromInline(t *testing.T) {
exp := &Filter{
Tenant: "cgrates.org",
ID: "*string:~*req.Account:~*uhc.<~*req.CGRID;-Account>;1001",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Account",
Values: []string{"~*uhc.<~*req.CGRID;-Account>", "1001"},
},
},
}
if err := exp.Compile(); err != nil {
t.Fatal(err)
}
if rcv, err := NewFilterFromInline("cgrates.org", "*string:~*req.Account:~*uhc.<~*req.CGRID;-Account>;1001"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(exp, rcv) {
t.Errorf("Expected: %s , received: %s", utils.ToJSON(exp), utils.ToJSON(rcv))
}
if _, err := NewFilterFromInline("cgrates.org", "*string:~*req.Account"); err == nil {
t.Error("Expected error received nil")
}
if _, err := NewFilterFromInline("cgrates.org", "*string:~*req.Account:~*req.CGRID{*;1001"); err == nil {
t.Error("Expected error received nil")
}
}

View File

@@ -1797,7 +1797,7 @@ func (tps TpFilterS) AsTPFilter() (result []*utils.TPFilterProfile) {
if tp.Type != utils.EmptyString {
var vals []string
if tp.Values != utils.EmptyString {
vals = strings.Split(tp.Values, utils.INFIELD_SEP)
vals = splitDynFltrValues(tp.Values)
}
th.Filters = append(th.Filters, &utils.TPFilter{
Type: tp.Type,

View File

@@ -1849,6 +1849,41 @@ func TestTPFilterAsTPFilter(t *testing.T) {
}
}
func TestTPFilterAsTPFilterWithDynValues(t *testing.T) {
tps := []*TpFilter{
{
Tpid: "TEST_TPID",
ID: "Filter1",
ActivationInterval: "2014-07-29T15:00:00Z;2014-08-29T15:00:00Z",
Type: utils.MetaString,
Element: "CustomField",
Values: "1001;~*uch.<~*rep.CGRID;~*rep.RunID;-Cost>;1002;~*uch.<~*rep.CGRID;~*rep.RunID>",
},
}
eTPs := []*utils.TPFilterProfile{
{
TPid: tps[0].Tpid,
ID: tps[0].ID,
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-29T15:00:00Z",
ExpiryTime: "2014-08-29T15:00:00Z",
},
Filters: []*utils.TPFilter{
{
Type: utils.MetaString,
Element: "CustomField",
Values: []string{"1001", "~*uch.<~*rep.CGRID;~*rep.RunID;-Cost>", "1002", "~*uch.<~*rep.CGRID;~*rep.RunID>"},
},
},
},
}
rcvTPs := TpFilterS(tps).AsTPFilter()
if !(reflect.DeepEqual(eTPs, rcvTPs) || reflect.DeepEqual(eTPs[0], rcvTPs[0])) {
t.Errorf("\nExpecting:\n%+v\nReceived:\n%+v", utils.ToIJSON(eTPs), utils.ToIJSON(rcvTPs))
}
}
func TestTPFilterAsTPFilter2(t *testing.T) {
tps := []*TpFilter{
{

View File

@@ -1360,7 +1360,12 @@ func testOnStorITTiming(t *testing.T) {
func testOnStorITCRUDHistory(t *testing.T) {
time := time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC)
ist := &utils.LoadInstance{"Load", "RatingLoad", "Account", time}
ist := &utils.LoadInstance{
LoadID: "Load",
RatingLoadID: "RatingLoad",
AccountingLoadID: "Account",
LoadTime: time,
}
if err := onStor.DataDB().AddLoadHistory(ist, 1, utils.NonTransactional); err != nil {
t.Error(err)
}
@@ -1506,9 +1511,9 @@ func testOnStorITStatQueue(t *testing.T) {
Answered: 2,
Count: 3,
Events: map[string]*StatWithCompress{
"cgrates.org:ev1": &StatWithCompress{Stat: 1},
"cgrates.org:ev2": &StatWithCompress{Stat: 1},
"cgrates.org:ev3": &StatWithCompress{Stat: 0},
"cgrates.org:ev1": {Stat: 1},
"cgrates.org:ev2": {Stat: 1},
"cgrates.org:ev3": {Stat: 0},
},
},
},
@@ -1539,9 +1544,9 @@ func testOnStorITStatQueue(t *testing.T) {
Answered: 3,
Count: 3,
Events: map[string]*StatWithCompress{
"cgrates.org:ev1": &StatWithCompress{Stat: 1},
"cgrates.org:ev2": &StatWithCompress{Stat: 1},
"cgrates.org:ev3": &StatWithCompress{Stat: 1},
"cgrates.org:ev1": {Stat: 1},
"cgrates.org:ev2": {Stat: 1},
"cgrates.org:ev3": {Stat: 1},
},
},
}
@@ -1707,6 +1712,9 @@ func testOnStorITFilter(t *testing.T) {
ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
},
}
if err := fp.Compile(); err != nil {
t.Fatal(err)
}
if _, rcvErr := onStor.GetFilter("cgrates.org", "Filter1",
true, false, utils.NonTransactional); rcvErr != nil && rcvErr != utils.ErrNotFound {
t.Error(rcvErr)
@@ -1747,6 +1755,9 @@ func testOnStorITFilter(t *testing.T) {
Values: []string{"10", "20"},
},
}
if err := fp.Compile(); err != nil {
t.Fatal(err)
}
if err := onStor.SetFilter(fp, true); err != nil {
t.Error(err)
}
@@ -2158,12 +2169,12 @@ func testOnStorITRateProfile(t *testing.T) {
MaxCost: 0.6,
MaxCostStrategy: "*free",
Rates: map[string]*Rate{
"FIRST_GI": &Rate{
"FIRST_GI": {
ID: "FIRST_GI",
FilterIDs: []string{"*gi:~*req.Usage:0"},
Weight: 0,
IntervalRates: []*IntervalRate{
&IntervalRate{
{
Value: 0.12,
Unit: time.Duration(1 * time.Minute),
Increment: time.Duration(1 * time.Minute),
@@ -2171,12 +2182,12 @@ func testOnStorITRateProfile(t *testing.T) {
},
Blocker: false,
},
"SECOND_GI": &Rate{
"SECOND_GI": {
ID: "SECOND_GI",
FilterIDs: []string{"*gi:~*req.Usage:1m"},
Weight: 10,
IntervalRates: []*IntervalRate{
&IntervalRate{
{
Value: 0.06,
Unit: time.Duration(1 * time.Minute),
Increment: time.Duration(1 * time.Second),

View File

@@ -675,7 +675,7 @@ func testV1FltrAccountsExistsDynamicaly(t *testing.T) {
ThresholdProfile: &engine.ThresholdProfile{
Tenant: "cgrates.org",
ID: "TH_AccountDinamic",
FilterIDs: []string{"*exists::~;*accounts.;~*req.Account"},
FilterIDs: []string{"*exists:~*accounts.<~*req.Account>:"},
MaxHits: -1,
MinSleep: time.Duration(1 * time.Millisecond),
Weight: 90.0,

View File

@@ -196,9 +196,30 @@ func testFltrITMigrateAndMove(t *testing.T) {
if err := fltrMigrator.dmIN.setV1Filter(fltr); err != nil {
t.Error("Error when setting v1 Filters ", err.Error())
}
if err := fltrMigrator.dmIN.DataManager().SetAttributeProfile(attrProf, true); err != nil {
if err := fltrMigrator.dmIN.DataManager().SetAttributeProfile(attrProf, false); err != nil {
t.Error("Error when setting attribute profile for v1 Filters ", err.Error())
}
// manually set the indexes because the GetFilter functions compile the value from DB that is still the old version
wrongFltrIdx := map[string]utils.StringSet{
"*prefix::1001": {"ATTR_1": struct{}{}},
"*string:Account:1001": {"ATTR_1": struct{}{}}}
if err := fltrMigrator.dmIN.DataManager().SetIndexes(
utils.CacheAttributeFilterIndexes,
utils.ConcatenatedKey(attrProf.Tenant, utils.META_ANY),
wrongFltrIdx, false, ""); err != nil {
t.Error(err)
}
wrongFltrIdx = map[string]utils.StringSet{
utils.CacheAttributeFilterIndexes: {"ATTR_1": struct{}{}},
}
if err := fltrMigrator.dmIN.DataManager().SetIndexes(
utils.CacheReverseFilterIndexes,
"cgrates.org:FLTR_2",
wrongFltrIdx, false, ""); err != nil {
t.Error(err)
}
currentVersion := engine.Versions{utils.RQF: 1}
err := fltrMigrator.dmIN.DataManager().DataDB().SetVersions(currentVersion, false)
if err != nil {
@@ -366,9 +387,32 @@ func testFltrITMigratev2(t *testing.T) {
if err := fltrMigrator.dmIN.setV1Filter(filters); err != nil {
t.Error("Error when setting v1 Filters ", err.Error())
}
if err := fltrMigrator.dmIN.DataManager().SetAttributeProfile(attrProf, true); err != nil {
if err := fltrMigrator.dmIN.DataManager().SetAttributeProfile(attrProf, false); err != nil {
t.Error("Error when setting attribute profile for v1 Filters ", err.Error())
}
// manually set the indexes because the GetFilter functions compile the value from DB that is still the old version
wrongFltrIdx := map[string]utils.StringSet{
"*string::1001": {"ATTR_1": struct{}{}},
"*string:~Account:1001": {"ATTR_1": struct{}{}}}
if err := fltrMigrator.dmIN.DataManager().SetIndexes(
utils.CacheAttributeFilterIndexes,
utils.ConcatenatedKey(attrProf.Tenant, utils.META_ANY),
wrongFltrIdx, false, ""); err != nil {
t.Error(err)
}
wrongFltrIdx = map[string]utils.StringSet{
utils.CacheAttributeFilterIndexes: {"ATTR_1": struct{}{}},
}
if err := fltrMigrator.dmIN.DataManager().SetIndexes(
utils.CacheReverseFilterIndexes,
"cgrates.org:FLTR_2",
wrongFltrIdx, false, ""); err != nil {
t.Error(err)
}
currentVersion := engine.Versions{utils.RQF: 2}
err := fltrMigrator.dmIN.DataManager().DataDB().SetVersions(currentVersion, false)
if err != nil {