diff --git a/apis/filters.go b/apis/filters.go index b0a800dce..a465cb608 100644 --- a/apis/filters.go +++ b/apis/filters.go @@ -192,3 +192,19 @@ func (admS *AdminSv1) GetFiltersCount(ctx *context.Context, args *utils.ArgsItem *reply = len(keys) return } + +// FiltersMatch checks whether a set of filter IDs passes for the provided CGREvent +func (admS *AdminSv1) FiltersMatch(ctx *context.Context, args *engine.ArgsFiltersMatch, reply *bool) (err error) { + tnt := args.Tenant + if tnt == utils.EmptyString { + tnt = admS.cfg.GeneralCfg().DefaultTenant + } + evDP := args.CGREvent.AsDataProvider() + var pass bool + if pass, err = admS.fltrS.Pass(ctx, tnt, args.FilterIDs, evDP); err != nil { + return + } else if pass { + *reply = true + } + return +} diff --git a/apis/filters_it_test.go b/apis/filters_it_test.go index 695c5cea4..d60cd61bc 100644 --- a/apis/filters_it_test.go +++ b/apis/filters_it_test.go @@ -64,6 +64,8 @@ var ( testFilterSSetGetFilterWithPrefix, testFilterSGetFiltersWithPrefix, testFilterSSetInvalidFilter, + testFilterSFiltersMatchTrue, + testFilterSFiltersMatchFalse, testFilterSKillEngine, } ) @@ -714,6 +716,56 @@ func testFilterSSetInvalidFilter(t *testing.T) { } } +func testFilterSFiltersMatchTrue(t *testing.T) { + args := &engine.ArgsFiltersMatch{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EventTest", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "1002", + }, + }, + FilterIDs: []string{ + "*string:~*req.Account:1001", + "*prefix:~*req.Destination:10", + }, + } + + var reply bool + if err := fltrSRPC.Call(context.Background(), utils.AdminSv1FiltersMatch, args, + &reply); err != nil { + t.Error(err) + } else if reply != true { + t.Error("expected reply to be", true) + } +} + +func testFilterSFiltersMatchFalse(t *testing.T) { + args := &engine.ArgsFiltersMatch{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EventTest", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "2002", + }, + }, + FilterIDs: []string{ + "*string:~*req.Account:1001", + "*prefix:~*req.Destination:10", + }, + } + + var reply bool + if err := fltrSRPC.Call(context.Background(), utils.AdminSv1FiltersMatch, args, + &reply); err != nil { + t.Error(err) + } else if reply != false { + t.Error("expected reply to be", false) + } +} + //Kill the engine when it is about to be finished func testFilterSKillEngine(t *testing.T) { if err := engine.KillEngine(100); err != nil { diff --git a/apis/filters_test.go b/apis/filters_test.go index fe4d17ccf..0a744b464 100644 --- a/apis/filters_test.go +++ b/apis/filters_test.go @@ -38,7 +38,7 @@ func TestFiltersSetGetGetCountFilters(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -204,7 +204,7 @@ func TestFiltersSetFiltersMissingField(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -228,7 +228,7 @@ func TestFiltersSetFiltersTenantEmpty(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ ID: "fltr_for_attr", @@ -278,7 +278,7 @@ func TestFiltersSetFiltersGetFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -332,7 +332,7 @@ func TestFiltersSetFiltersError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -376,7 +376,7 @@ func TestFiltersSetFiltersSetFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -439,7 +439,7 @@ func TestFiltersSetFiltersComposeCacheArgsForFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -504,7 +504,7 @@ func TestFiltersSetFiltersSetLoadIDsError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -569,7 +569,7 @@ func TestFiltersSetFiltersCacheForFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ Tenant: utils.CGRateSorg, @@ -606,7 +606,7 @@ func TestFiltersGetFilterNoTenant(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ ID: "fltr_for_attr", @@ -652,7 +652,7 @@ func TestFiltersGetFilterMissingField(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) fltr := &engine.FilterWithAPIOpts{ Filter: &engine.Filter{ ID: "fltr_for_attr", @@ -698,7 +698,7 @@ func TestFiltersGetFilterGetFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var replyGet engine.Filter argsGet := &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{ @@ -724,7 +724,7 @@ func TestFiltersGetFiltersCountError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var reply int args := &utils.ArgsItemIDs{} @@ -742,7 +742,7 @@ func TestFiltersRemoveFilterMissingStructFieldError(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var reply string args := &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{}, @@ -767,7 +767,7 @@ func TestFiltersRemoveFilterRemoveFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var reply string args := &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{ @@ -1161,7 +1161,7 @@ func TestFiltersRemoveFilterSetLoadIDsError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var reply string args := &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{ @@ -1208,7 +1208,7 @@ func TestFiltersRemoveFilterCallCacheForFilterError(t *testing.T) { }, } dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) var reply string args := &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{ @@ -1233,7 +1233,7 @@ func TestFiltersGetFilterIDs(t *testing.T) { connMgr := engine.NewConnManager(cfg) dataDB := &engine.DataDBMock{} dm := engine.NewDataManager(dataDB, nil, connMgr) - admS := NewAdminSv1(cfg, dm, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr, nil) args6 := &utils.ArgsItemIDs{} var reply6 []string @@ -1292,3 +1292,95 @@ func TestFiltersValidateFilterRuleErr(t *testing.T) { t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err) } } + +func TestFiltersFiltersMatchTrue(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), connMgr) + fltrS := engine.NewFilterS(cfg, connMgr, dm) + admS := NewAdminSv1(cfg, dm, connMgr, fltrS) + args := &engine.ArgsFiltersMatch{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EventTest", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "1002", + }, + }, + FilterIDs: []string{ + "*string:~*req.Account:1001", + "*prefix:~*req.Destination:10", + }, + } + var reply bool + if err := admS.FiltersMatch(context.Background(), args, &reply); err != nil { + t.Error(err) + } else if reply != true { + t.Errorf("expected reply to be <%+v>", true) + } +} + +func TestFiltersFiltersMatchFalse(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), connMgr) + fltrS := engine.NewFilterS(cfg, connMgr, dm) + admS := NewAdminSv1(cfg, dm, connMgr, fltrS) + args := &engine.ArgsFiltersMatch{ + CGREvent: &utils.CGREvent{ + ID: "EventTest", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "2002", + }, + }, + FilterIDs: []string{ + "*string:~*req.Account:1001", + "*prefix:~*req.Destination:10", + }, + } + var reply bool + if err := admS.FiltersMatch(context.Background(), args, &reply); err != nil { + t.Error(err) + } else if reply != false { + t.Errorf("expected reply to be <%+v>", false) + } +} + +func TestFiltersFiltersMatchErr(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), connMgr) + fltrS := engine.NewFilterS(cfg, connMgr, dm) + admS := NewAdminSv1(cfg, dm, connMgr, fltrS) + args := &engine.ArgsFiltersMatch{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EventTest", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "1002", + }, + }, + FilterIDs: []string{ + "*string.invalid:filter", + }, + } + experr := `inline parse error for string: <*string.invalid:filter>` + var reply bool + if err := admS.FiltersMatch(context.Background(), args, &reply); err == nil || err.Error() != experr { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err) + } else if reply != false { + t.Errorf("expected reply to be <%+v>", false) + } +} diff --git a/utils/consts.go b/utils/consts.go index cc6c6cbc9..69471e71d 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1162,6 +1162,7 @@ const ( AdminSv1GetFilterIDs = "AdminSv1.GetFilterIDs" AdminSv1GetFiltersCount = "AdminSv1.GetFiltersCount" AdminSv1GetFilters = "AdminSv1.GetFilters" + AdminSv1FiltersMatch = "AdminSv1.FiltersMatch" // APIerSv1SetDataDBVersions = "APIerSv1.SetDataDBVersions" // APIerSv1GetActions = "APIerSv1.GetActions"