diff --git a/engine/filters.go b/engine/filters.go index b4cb5be6f..0ebca19ff 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -207,15 +207,15 @@ func (fltr *FilterRule) Pass(fieldNameDP utils.DataProvider, } switch fltr.Type { - case utils.MetaString, utils.MetaNotString: + case utils.MetaString, utils.MetaNotString, utils.MetaNIString: result, err = fltr.passString(fieldNameDP, fieldValuesDP) case utils.MetaEmpty, utils.MetaNotEmpty: result, err = fltr.passEmpty(fieldNameDP) - case utils.MetaExists, utils.MetaNotExists: + case utils.MetaExists, utils.MetaNotExists, utils.MetaNIExists: result, err = fltr.passExists(fieldNameDP) - case utils.MetaPrefix, utils.MetaNotPrefix: + case utils.MetaPrefix, utils.MetaNotPrefix, utils.MetaNIPrefix: result, err = fltr.passStringPrefix(fieldNameDP, fieldValuesDP) - case utils.MetaSuffix, utils.MetaNotSuffix: + case utils.MetaSuffix, utils.MetaNotSuffix, utils.MetaNISuffix: result, err = fltr.passStringSuffix(fieldNameDP, fieldValuesDP) case utils.MetaTimings, utils.MetaNotTimings: result, err = fltr.passTimings(fieldNameDP, fieldValuesDP) diff --git a/engine/filters_test.go b/engine/filters_test.go index 6aaa7c1a4..e86ce8bd4 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -3140,3 +3140,288 @@ func TestFiltersgetFieldValueDataProvider(t *testing.T) { }) } } + +func TestFiltersPassNIString(t *testing.T) { + ev := utils.MapStorage{ + utils.MetaReq: map[string]any{ + utils.Destination: "1002", + utils.Category: "call", + }, + } + + tests := []struct { + name string + fltr *FilterRule + want bool + }{ + { + name: "NIStringMatch", + fltr: &FilterRule{ + Type: utils.MetaNIString, + Element: "~*req.Category", + Values: []string{"call"}, + }, + want: true, + }, + { + name: "NIStringNotMatch", + fltr: &FilterRule{ + Type: utils.MetaNIString, + Element: "~*req.Category", + Values: []string{"premium"}, + }, + want: false, + }, + { + name: "NIStringMultipleValues", + fltr: &FilterRule{ + Type: utils.MetaNIString, + Element: "~*req.Destination", + Values: []string{"1001", "1002", "1003"}, + }, + want: true, + }, + } + var fS *FilterS + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.fltr.CompileValues(); err != nil { + t.Fatal(err) + } + fieldNameDP, err := fS.getFieldNameDataProvider(ev, tt.fltr.Element, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + fieldValuesDP, err := fS.getFieldValuesDataProviders(ev, tt.fltr.Values, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + got, gotErr := tt.fltr.Pass(fieldNameDP, fieldValuesDP) + if gotErr != nil { + t.Errorf("Pass() failed: %v", gotErr) + return + } + if got != tt.want { + t.Errorf("Pass() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFiltersPassNISuffix(t *testing.T) { + ev := utils.MapStorage{ + utils.MetaReq: map[string]any{ + utils.Account: "1001", + utils.Destination: "+4985837291", + utils.Category: "call", + }, + } + + tests := []struct { + name string + fltr *FilterRule + want bool + }{ + { + name: "MatchingNISuffix", + fltr: &FilterRule{ + Type: utils.MetaNISuffix, + Element: "~*req.Destination", + Values: []string{"91"}, + }, + want: true, + }, + { + name: "NonMatchingSuffix", + fltr: &FilterRule{ + Type: utils.MetaNISuffix, + Element: "~*req.Account", + Values: []string{"02"}, + }, + want: false, + }, + { + name: "NISuffixPassMultipleValues", + fltr: &FilterRule{ + Type: utils.MetaNISuffix, + Element: "~*req.Destination", + Values: []string{"3", "91", "22"}, + }, + want: true, + }, + } + + var fS *FilterS + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.fltr.CompileValues(); err != nil { + t.Fatal(err) + } + fieldNameDP, err := fS.getFieldNameDataProvider(ev, tt.fltr.Element, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + fieldValuesDP, err := fS.getFieldValuesDataProviders(ev, tt.fltr.Values, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + got, err := tt.fltr.Pass(fieldNameDP, fieldValuesDP) + if err != nil { + t.Errorf("Pass() error = %v", err) + return + } + if got != tt.want { + t.Errorf("Pass() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFiltersPassNIExists(t *testing.T) { + ev := utils.MapStorage{ + utils.MetaReq: map[string]any{ + utils.Account: "1001", + utils.Destination: "1002", + utils.Category: "call", + }, + } + + tests := []struct { + name string + fltr *FilterRule + want bool + }{ + { + name: "NIExistsField", + fltr: &FilterRule{ + Type: utils.MetaNIExists, + Element: "~*req.Category", + Values: []string{}, + }, + want: true, + }, + { + name: "NonNIExistentField", + fltr: &FilterRule{ + Type: utils.MetaNIExists, + Element: "~*req.NonExistentField", + Values: []string{}, + }, + want: false, + }, + { + name: "NIExistsAccount", + fltr: &FilterRule{ + Type: utils.MetaNIExists, + Element: "~*req.Account", + Values: []string{}, + }, + want: true, + }, + { + name: "NIExistsDestination", + fltr: &FilterRule{ + Type: utils.MetaNIExists, + Element: "~*req.Destination", + Values: []string{}, + }, + want: true, + }, + } + + var fS *FilterS + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.fltr.CompileValues(); err != nil { + t.Fatal(err) + } + + fieldNameDP, err := fS.getFieldNameDataProvider(ev, tt.fltr.Element, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + fieldValuesDP, err := fS.getFieldValuesDataProviders(ev, tt.fltr.Values, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + + got, err := tt.fltr.Pass(fieldNameDP, fieldValuesDP) + if err != nil { + t.Errorf("Pass() error = %v", err) + return + } + if got != tt.want { + t.Errorf("Pass() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFiltersPassNIPrefix(t *testing.T) { + ev := utils.MapStorage{ + utils.MetaReq: map[string]any{ + utils.Account: "1001", + utils.Destination: "+4985837291", + utils.Category: "call", + }, + } + + tests := []struct { + name string + fltr *FilterRule + want bool + }{ + { + name: "MatchingNIPrefix", + fltr: &FilterRule{ + Type: utils.MetaNIPrefix, + Element: "~*req.Destination", + Values: []string{"+49"}, + }, + want: true, + }, + { + name: "NonMatchingNIPrefix", + fltr: &FilterRule{ + Type: utils.MetaNIPrefix, + Element: "~*req.Account", + Values: []string{"20"}, + }, + want: false, + }, + { + name: "NIPrefixPassMultipleValues", + fltr: &FilterRule{ + Type: utils.MetaNIPrefix, + Element: "~*req.Destination", + Values: []string{"+49", "+21", "+35"}, + }, + want: true, + }, + } + + var fS *FilterS + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.fltr.CompileValues(); err != nil { + t.Fatal(err) + } + fieldNameDP, err := fS.getFieldNameDataProvider(ev, tt.fltr.Element, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + fieldValuesDP, err := fS.getFieldValuesDataProviders(ev, tt.fltr.Values, utils.EmptyString) + if err != nil { + t.Fatal(err) + } + got, err := tt.fltr.Pass(fieldNameDP, fieldValuesDP) + if err != nil { + t.Errorf("Pass() error = %v", err) + return + } + if got != tt.want { + t.Errorf("Pass() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/utils/consts.go b/utils/consts.go index ab6830e40..c11303f5e 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -908,6 +908,12 @@ const ( MetaNotEqual = "*noteq" MetaEC = "*ec" + + // not indexed + MetaNIString = "*nistring" + MetaNIPrefix = "*niprefix" + MetaNIExists = "*niexists" + MetaNISuffix = "*nisuffix" ) // ReplicatorSv1 APIs