diff --git a/engine/filters.go b/engine/filters.go index 3e5d91ac1..90a332dc6 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -35,6 +35,7 @@ const ( MetaPrefix = "*prefix" MetaSuffix = "*suffix" MetaEmpty = "*empty" + MetaExists = "*exists" MetaTimings = "*timings" MetaRSR = "*rsr" MetaStatS = "*stats" @@ -162,12 +163,12 @@ func NewFilterRule(rfType, fieldName string, vals []string) (*FilterRule, error) negative = true } if !utils.IsSliceMember([]string{MetaString, MetaPrefix, MetaSuffix, - MetaTimings, MetaRSR, MetaStatS, MetaDestinations, MetaEmpty, + MetaTimings, MetaRSR, MetaStatS, MetaDestinations, MetaEmpty, MetaExists, MetaLessThan, MetaLessOrEqual, MetaGreaterThan, MetaGreaterOrEqual}, rfType) { return nil, fmt.Errorf("Unsupported filter Type: %s", rfType) } if fieldName == "" && utils.IsSliceMember([]string{MetaString, MetaPrefix, MetaSuffix, - MetaTimings, MetaDestinations, MetaLessThan, MetaEmpty, + MetaTimings, MetaDestinations, MetaLessThan, MetaEmpty, MetaExists, MetaLessOrEqual, MetaGreaterThan, MetaGreaterOrEqual}, rfType) { return nil, fmt.Errorf("FieldName is mandatory for Type: %s", rfType) } @@ -251,6 +252,8 @@ func (fltr *FilterRule) Pass(dP config.DataProvider, rpcClnt rpcclient.RpcClient result, err = fltr.passString(dP) case MetaEmpty: result, err = fltr.passEmpty(dP) + case MetaExists: + result, err = fltr.passExists(dP) case MetaPrefix: result, err = fltr.passStringPrefix(dP) case MetaSuffix: @@ -290,6 +293,17 @@ func (fltr *FilterRule) passString(dP config.DataProvider) (bool, error) { return false, nil } +func (fltr *FilterRule) passExists(dP config.DataProvider) (bool, error) { + _, err := dP.FieldAsInterface(strings.Split(fltr.FieldName, utils.NestingSep)) + if err != nil { + if err == utils.ErrNotFound { + return false, nil + } + return false, err + } + return true, nil +} + func (fltr *FilterRule) passEmpty(dP config.DataProvider) (bool, error) { val, err := dP.FieldAsInterface(strings.Split(fltr.FieldName, utils.NestingSep)) if err != nil { diff --git a/engine/filters_test.go b/engine/filters_test.go index 3cac4d33f..b1122ff3d 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -114,6 +114,58 @@ func TestFilterPassEmpty(t *testing.T) { } } +func TestFilterPassExists(t *testing.T) { + cd := &CallDescriptor{ + Direction: "*out", + Category: "", + Tenant: "cgrates.org", + Subject: "dan", + Destination: "+4986517174963", + TimeStart: time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC), + TimeEnd: time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC), + DurationIndex: 132 * time.Second, + ExtraFields: map[string]string{"navigation": "off"}, + } + rf := &FilterRule{Type: MetaExists, FieldName: "Category", Values: []string{}} + if passes, err := rf.passExists(cd); err != nil { + t.Error(err) + } else if !passes { + t.Error("Not passes filter") + } + rf = &FilterRule{Type: MetaExists, FieldName: "Direction", Values: []string{}} + if passes, err := rf.passExists(cd); err != nil { + t.Error(err) + } else if !passes { + t.Error("Not passes filter") + } + rf = &FilterRule{Type: MetaExists, FieldName: "ExtraFields1", Values: []string{}} + if passes, err := rf.passExists(cd); err != nil { + t.Error(err) + } else if passes { + t.Error("Filter passes") + } + cd.ExtraFields = map[string]string{} + rf = &FilterRule{Type: MetaExists, FieldName: "ExtraFields", Values: []string{}} + if passes, err := rf.passExists(cd); err != nil { + t.Error(err) + } else if !passes { + t.Error("Not passes filter") + } + //not + rf = &FilterRule{Type: "*notexists", FieldName: "Direction", Values: []string{}} + if passes, err := rf.Pass(cd, nil); err != nil { + t.Error(err) + } else if passes { + t.Error("Filter passes") + } + rf = &FilterRule{Type: "*notexists", FieldName: "Category1", Values: []string{}} + if passes, err := rf.Pass(cd, nil); err != nil { + t.Error(err) + } else if !passes { + t.Error("Not passes filter") + } +} + func TestFilterPassStringPrefix(t *testing.T) { cd := &CallDescriptor{ Direction: "*out", @@ -409,6 +461,14 @@ func TestFilterNewRequestFilter(t *testing.T) { if !reflect.DeepEqual(erf, rf) { t.Errorf("Expecting: %+v, received: %+v", erf, rf) } + rf, err = NewFilterRule(MetaExists, "MetaExists", []string{}) + if err != nil { + t.Errorf("Error: %+v", err) + } + erf = &FilterRule{Type: MetaExists, FieldName: "MetaExists", Values: []string{}} + if !reflect.DeepEqual(erf, rf) { + t.Errorf("Expecting: %+v, received: %+v", erf, rf) + } rf, err = NewFilterRule(MetaPrefix, "MetaPrefix", []string{"stringPrefix"}) if err != nil { t.Errorf("Error: %+v", err) @@ -656,6 +716,18 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) { t.Errorf("For %s expecting: %+v, received: %+v", key, true, pass) } } + if pass, err := filterS.Pass("cgrates.org", []string{"*exists:" + "NewKey" + ":"}, + config.NewNavigableMap(failEvent)); err != nil { + t.Errorf(err.Error()) + } else if pass { + t.Errorf("For NewKey expecting: %+v, received: %+v", false, pass) + } + if pass, err := filterS.Pass("cgrates.org", []string{"*notexists:" + "NewKey" + ":"}, + config.NewNavigableMap(failEvent)); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("For NewKey expecting: %+v, received: %+v", true, pass) + } } func TestPassFiltersForEventWithEmptyFilter(t *testing.T) { diff --git a/engine/poster_test.go b/engine/poster_test.go deleted file mode 100644 index c607b0784..000000000 --- a/engine/poster_test.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ -package engine