diff --git a/engine/filters.go b/engine/filters.go index 2f5f7bfd7..7b0144c4a 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -836,6 +836,12 @@ func CheckFilter(fltr *Filter) (err error) { return fmt.Errorf("%s for filter <%v>", err, fltr) //encapsulated error } for _, val := range rls.Values { + if rls.Type == utils.MetaEmpty || rls.Type == utils.MetaNotEmpty || + rls.Type == utils.MetaExists || rls.Type == utils.MetaNotExists && + val != utils.EmptyString { + return fmt.Errorf("value of filter <%s> is not empty <%s>", + fltr.ID, val) + } if err = valFunc(val); err != nil { return fmt.Errorf("%s for filter <%v>", err, fltr) //encapsulated error } diff --git a/engine/filters_test.go b/engine/filters_test.go index f9ccdc01d..1293ffab2 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -2230,7 +2230,6 @@ func TestFilterRulePassRegexParseErr(t *testing.T) { } } func TestCheckFilterErrValFuncElement(t *testing.T) { - fltr := &Filter{ Tenant: utils.CGRateSorg, ID: "FLTR_CP_1", @@ -2243,13 +2242,12 @@ func TestCheckFilterErrValFuncElement(t *testing.T) { }, } expErr := `Path is missing for filter <{"Tenant":"cgrates.org","ID":"FLTR_CP_1","Rules":[{"Type":"*string","Element":"~missing path","Values":["ChargerProfile1"]}]}>` - if err := CheckFilter(fltr); err.Error() != expErr { + if err := CheckFilter(fltr); err == nil || err.Error() != expErr { t.Error(err) } } func TestCheckFilterErrValFuncValues(t *testing.T) { - fltr := &Filter{ Tenant: utils.CGRateSorg, ID: "FLTR_CP_1", @@ -2262,7 +2260,25 @@ func TestCheckFilterErrValFuncValues(t *testing.T) { }, } expErr := `Path is missing for filter <{"Tenant":"cgrates.org","ID":"FLTR_CP_1","Rules":[{"Type":"*string","Element":"~*req.Charger","Values":["~missing path"]}]}>` - if err := CheckFilter(fltr); err.Error() != expErr { + if err := CheckFilter(fltr); err == nil || err.Error() != expErr { + t.Error(err) + } +} + +func TestCheckFilterErrNotEmpty(t *testing.T) { + fltr := &Filter{ + Tenant: utils.CGRateSorg, + ID: "FLTR_CP_1", + Rules: []*FilterRule{ + { + Type: utils.MetaNotEmpty, + Element: "~*req.Charger", + Values: []string{"''"}, + }, + }, + } + expErr := `value of filter is not empty <''>` + if err := CheckFilter(fltr); err == nil || err.Error() != expErr { t.Error(err) } } diff --git a/engine/storage_mysql.go b/engine/storage_mysql.go index 9ae781c4e..34b81acdc 100644 --- a/engine/storage_mysql.go +++ b/engine/storage_mysql.go @@ -136,7 +136,7 @@ func (msqlS *MySQLStorage) valueQry(ruleType, elem, field string, values []strin conditions = append(conditions, fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') != ''", elem, field)) return } - conditions = append(conditions, fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') != ''", elem, field)) + conditions = append(conditions, fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') == ''", elem, field)) } return } @@ -153,13 +153,14 @@ func (msqlS *MySQLStorage) valueQry(ruleType, elem, field string, values []strin } singleCond = fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') = '%s'", elem, field, value) case utils.MetaLessThan, utils.MetaLessOrEqual, utils.MetaGreaterThan, utils.MetaGreaterOrEqual: - if ruleType == utils.MetaGreaterOrEqual { + switch ruleType { + case utils.MetaGreaterOrEqual: singleCond = fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') >= %s", elem, field, value) - } else if ruleType == utils.MetaGreaterThan { + case utils.MetaGreaterThan: singleCond = fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') > %s", elem, field, value) - } else if ruleType == utils.MetaLessOrEqual { + case utils.MetaLessOrEqual: singleCond = fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') <= %s", elem, field, value) - } else if ruleType == utils.MetaLessThan { + case utils.MetaLessThan: singleCond = fmt.Sprintf(" JSON_VALUE(%s, '$.\"%s\"') < %s", elem, field, value) } case utils.MetaPrefix, utils.MetaNotPrefix: diff --git a/engine/storage_postgres.go b/engine/storage_postgres.go index 2873e3b97..573df1105 100644 --- a/engine/storage_postgres.go +++ b/engine/storage_postgres.go @@ -161,13 +161,14 @@ func (poS *PostgresStorage) valueQry(ruleType, elem, field string, values []stri } singleCond = fmt.Sprintf(" (%s ->> '%s') = '%s'", elem, field, value) case utils.MetaLessThan, utils.MetaLessOrEqual, utils.MetaGreaterThan, utils.MetaGreaterOrEqual: - if ruleType == utils.MetaGreaterOrEqual { + switch ruleType { + case utils.MetaGreaterOrEqual: singleCond = fmt.Sprintf(" (%s ->> '%s')::numeric >= '%s'", elem, field, value) - } else if ruleType == utils.MetaGreaterThan { + case utils.MetaGreaterThan: singleCond = fmt.Sprintf(" (%s ->> '%s')::numeric > '%s'", elem, field, value) - } else if ruleType == utils.MetaLessOrEqual { + case utils.MetaLessOrEqual: singleCond = fmt.Sprintf(" (%s ->> '%s')::numeric <= '%s'", elem, field, value) - } else if ruleType == utils.MetaLessThan { + case utils.MetaLessThan: singleCond = fmt.Sprintf(" (%s ->> '%s')::numeric < '%s'", elem, field, value) } case utils.MetaPrefix, utils.MetaNotPrefix: diff --git a/sessions/basics_it_test.go b/sessions/basics_it_test.go index e3c80567a..c16929c2a 100644 --- a/sessions/basics_it_test.go +++ b/sessions/basics_it_test.go @@ -30,10 +30,17 @@ import ( ) func TestSessionBasics(t *testing.T) { + var dbcfg engine.DBCfg switch *utils.DBType { case utils.MetaInternal: - case utils.MetaMySQL, utils.MetaMongo, utils.MetaPostgres: - t.SkipNow() + dbcfg = engine.InternalDBCfg + case utils.MetaMySQL: + case utils.MetaMongo: + t.SkipNow() // unfinished look into errors + dbcfg = engine.MongoDBCfg + case utils.MetaPostgres: + t.SkipNow() // unfinished look into postgres flush + dbcfg = engine.PostgresDBCfg default: t.Fatal("unsupported dbtype value") } @@ -72,7 +79,7 @@ cgrates.org,RP_STANDARD,,;10,,,,RT_STANDARD,*string:~*req.Destination:1002,"* * cgrates.org,RP_STANDARD,,,,,,RT_STANDARD,,,,,1m,0,0.6,1m,1s cgrates.org,RP_FALLBACK,,;0,,,,RT_FALLBACK,*string:~*req.Destination:1002,"* * * * *",;0,false,0s,0,0.01,1s,1s`, }, - DBCfg: engine.InternalDBCfg, + DBCfg: dbcfg, Encoding: *utils.Encoding, // LogBuffer: new(bytes.Buffer), } @@ -157,6 +164,9 @@ cgrates.org,RP_FALLBACK,,;0,,,,RT_FALLBACK,*string:~*req.Destination:1002,"* * * &utils.CDRFilters{ FilterIDs: []string{ fmt.Sprintf("*string:~*opts.*originID:%s", originID), + "*exists:~*opts.*originID:", + "*notexists:~*req.NonExistentField:", + "*notempty:~*opts.*originID:", }, }, &cdrs); err != nil { t.Fatal(err) @@ -187,12 +197,30 @@ cgrates.org,RP_FALLBACK,,;0,,,,RT_FALLBACK,*string:~*req.Destination:1002,"* * * switch costKey { case utils.Abstracts, utils.Concretes: cd := getCostDetails(t, cdr, utils.MetaAccountSCost) - got = cd[costKey].(float64) + if cd == nil { + t.Fatalf("Nil costDetails") + } + var canCast bool + got, canCast = cd[costKey].(float64) + if !canCast { + t.Fatalf("Could not cast cdr.Opts[utils.MetaCost] to float64") + } case utils.Cost: cd := getCostDetails(t, cdr, utils.MetaRateSCost) - got = cd[costKey].(float64) + if cd == nil { + t.Fatalf("Nil costDetails") + } + var canCast bool + got, canCast = cd[costKey].(float64) + if !canCast { + t.Fatalf("Could not cast cdr.Opts[utils.MetaCost] to float64") + } case utils.MetaCost: - got = cdr.Opts[utils.MetaCost].(float64) + var canCast bool + got, canCast = cdr.Opts[utils.MetaCost].(float64) + if !canCast { + t.Fatalf("Could not cast cdr.Opts[utils.MetaCost] to float64") + } default: t.Fatalf("invalid cdr cost key: %q", costKey) }