diff --git a/apis/dispatchers_test.go b/apis/dispatchers_test.go index c1ce685ce..4ee2443ed 100644 --- a/apis/dispatchers_test.go +++ b/apis/dispatchers_test.go @@ -23,6 +23,7 @@ import ( "sort" "testing" + "github.com/cgrates/birpc" "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -138,3 +139,692 @@ func TestDispatchersGetDispatcherProfilesOK(t *testing.T) { } } } + +func TestDispatchersSetGetRemDispatcherProfile(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "dspID", + }, + } + var result engine.DispatcherProfile + var reply string + + dspPrf := &DispatcherWithAPIOpts{ + DispatcherProfile: &engine.DispatcherProfile{ + Tenant: "cgrates.org", + ID: "dspID", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Hosts: engine.DispatcherHostProfiles{ + { + ID: "Host1", + }, + }, + Weight: 10, + }, + APIOpts: nil, + } + + if err := adms.SetDispatcherProfile(context.Background(), dspPrf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("\nexpected: <%+v>, received: <%+v>", utils.OK, reply) + } + + if err := adms.GetDispatcherProfile(context.Background(), arg, &result); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(result, *dspPrf.DispatcherProfile) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(dspPrf.DispatcherProfile), utils.ToJSON(result)) + } + + var dspPrfIDs []string + expDspPrfIDs := []string{"dspID"} + + if err := adms.GetDispatcherProfileIDs(context.Background(), &utils.ArgsItemIDs{}, + &dspPrfIDs); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(dspPrfIDs, expDspPrfIDs) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", expDspPrfIDs, dspPrfIDs) + } + + var rplyCount int + + if err := adms.GetDispatcherProfilesCount(context.Background(), &utils.ArgsItemIDs{}, + &rplyCount); err != nil { + t.Error(err) + } else if rplyCount != len(dspPrfIDs) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", len(dspPrfIDs), rplyCount) + } + + if err := adms.RemoveDispatcherProfile(context.Background(), arg, &reply); err != nil { + t.Error(err) + } + + engine.Cache.Clear(nil) + if err := adms.GetDispatcherProfile(context.Background(), arg, &result); err == nil || + err != utils.ErrNotFound { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersGetDispatcherProfileCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + var rcv engine.DispatcherProfile + experr := "MANDATORY_IE_MISSING: [ID]" + + if err := adms.GetDispatcherProfile(context.Background(), &utils.TenantIDWithAPIOpts{}, &rcv); err == nil || + err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + adms.dm = nil + experr = "SERVER_ERROR: NO_DATABASE_CONNECTION" + + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersGetDispatcherProfileCheckErrors", + }, + } + + if err := adms.GetDispatcherProfile(context.Background(), arg, &rcv); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersSetDispatcherProfileCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + + dspPrf := &DispatcherWithAPIOpts{ + DispatcherProfile: &engine.DispatcherProfile{}, + } + + var reply string + experr := "MANDATORY_IE_MISSING: [ID]" + + if err := adms.SetDispatcherProfile(context.Background(), dspPrf, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dspPrf.ID = "TestDispatchersSetDispatcherProfileCheckErrors" + dspPrf.FilterIDs = []string{"invalid_filter_format"} + experr = "SERVER_ERROR: broken reference to filter: for item with ID: cgrates.org:TestDispatchersSetDispatcherProfileCheckErrors" + + if err := adms.SetDispatcherProfile(context.Background(), dspPrf, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dspPrf.FilterIDs = []string{} + adms.connMgr = engine.NewConnManager(cfg) + adms.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), utils.CacheSv1, make(chan birpc.ClientConnector)) + ctx, cancel := context.WithTimeout(context.Background(), 10) + experr = "SERVER_ERROR: context deadline exceeded" + cfg.GeneralCfg().DefaultCaching = utils.MetaRemove + if err := adms.SetDispatcherProfile(ctx, dspPrf, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected <%+v>,\nreceived <%+v>", experr, err) + } + cancel() + + dbMock := &engine.DataDBMock{ + GetDispatcherProfileDrvF: func(*context.Context, string, string) (*engine.DispatcherProfile, error) { + dspPrf := &engine.DispatcherProfile{ + Tenant: "cgrates.org", + ID: "TEST", + } + return dspPrf, nil + }, + SetDispatcherProfileDrvF: func(*context.Context, *engine.DispatcherProfile) error { + return nil + }, + RemoveDispatcherProfileDrvF: func(*context.Context, string, string) error { + return nil + }, + GetKeysForPrefixF: func(c *context.Context, s string) ([]string, error) { + return nil, nil + }, + } + + adms.dm = engine.NewDataManager(dbMock, cfg.CacheCfg(), nil) + experr = "SERVER_ERROR: NOT_IMPLEMENTED" + + if err := adms.SetDispatcherProfile(context.Background(), dspPrf, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected <%+v>, \nreceived <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersRemoveDispatcherProfileCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + + dspPrf := &DispatcherWithAPIOpts{ + DispatcherProfile: &engine.DispatcherProfile{ + ID: "TestDispatchersRemoveDispatcherProfileCheckErrors", + Tenant: "cgrates.org", + Hosts: engine.DispatcherHostProfiles{ + { + ID: "HOST", + }, + }, + Weight: 10, + }, + } + var reply string + + if err := adms.SetDispatcherProfile(context.Background(), dspPrf, &reply); err != nil { + t.Error(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 10) + adms.cfg.GeneralCfg().DefaultCaching = "not_a_caching_type" + adms.connMgr = engine.NewConnManager(cfg) + adms.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), utils.CacheSv1, make(chan birpc.ClientConnector)) + experr := "SERVER_ERROR: context deadline exceeded" + + if err := adms.RemoveDispatcherProfile(ctx, &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherProfileCheckErrors", + }, + }, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + cancel() + + adms.cfg.GeneralCfg().DefaultCaching = utils.MetaNone + var rcv engine.DispatcherProfile + + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherProfileCheckErrors", + }, + } + + if err := adms.GetDispatcherProfile(context.Background(), arg, &rcv); err == nil || err != utils.ErrNotFound { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err) + } + + experr = "MANDATORY_IE_MISSING: [ID]" + + if err := adms.RemoveDispatcherProfile(context.Background(), + &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{}}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected <%+v>, \nreceived: <%+v>", experr, err) + } + + adms.dm = nil + experr = "SERVER_ERROR: NO_DATABASE_CONNECTION" + + if err := adms.RemoveDispatcherProfile(context.Background(), &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherProfileCheckErrors", + }}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dbMock := &engine.DataDBMock{ + GetDispatcherProfileDrvF: func(*context.Context, string, string) (*engine.DispatcherProfile, error) { + dspPrf := &engine.DispatcherProfile{ + Tenant: "cgrates.org", + ID: "TEST", + } + return dspPrf, nil + }, + SetDispatcherProfileDrvF: func(*context.Context, *engine.DispatcherProfile) error { + return nil + }, + RemoveDispatcherProfileDrvF: func(*context.Context, string, string) error { + return nil + }, + GetKeysForPrefixF: func(c *context.Context, s string) ([]string, error) { + return nil, nil + }, + SetIndexesDrvF: func(ctx *context.Context, idxItmType, tntCtx string, indexes map[string]utils.StringSet, commit bool, transactionID string) (err error) { + return nil + }, + GetIndexesDrvF: func(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error) { + return map[string]utils.StringSet{}, nil + }, + RemoveDispatcherHostDrvF: func(ctx *context.Context, tnt, id string) error { + return nil + }, + } + + engine.Cache.Clear(nil) + adms.dm = engine.NewDataManager(dbMock, cfg.CacheCfg(), nil) + experr = "SERVER_ERROR: NOT_IMPLEMENTED" + + if err := adms.RemoveDispatcherProfile(context.Background(), + &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherProfileCheckErrors", + }}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersGetDispatcherHostsOK(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, nil, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr) + args1 := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "test_ID1", + Reconnects: -1, + }, + }, + APIOpts: nil, + } + + var setReply string + if err := admS.SetDispatcherHost(context.Background(), args1, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + args2 := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "test_ID2", + Reconnects: -1, + }, + }, + APIOpts: nil, + } + + if err := admS.SetDispatcherHost(context.Background(), args2, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + // this Host will not match + args3 := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "test2_ID1", + Reconnects: -1, + }, + }, + APIOpts: nil, + } + + if err := admS.SetDispatcherHost(context.Background(), args3, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + argsGet := &utils.ArgsItemIDs{ + Tenant: "cgrates.org", + ItemsPrefix: "test_ID", + } + exp := []*engine.DispatcherHost{ + { + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "test_ID1", + Reconnects: -1, + }, + }, + { + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "test_ID2", + Reconnects: -1, + }, + }, + } + + var getReply []*engine.DispatcherHost + if err := admS.GetDispatcherHosts(context.Background(), argsGet, &getReply); err != nil { + t.Error(err) + } else { + sort.Slice(getReply, func(i, j int) bool { + return getReply[i].ID < getReply[j].ID + }) + if !reflect.DeepEqual(getReply, exp) { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(getReply)) + } + } +} + +func TestDispatchersSetGetRemDispatcherHost(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "dspHost1", + }, + } + var result engine.DispatcherHost + var reply string + + dspHost := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "dspHost1", + Reconnects: -1, + }, + }, + APIOpts: nil, + } + + if err := adms.SetDispatcherHost(context.Background(), dspHost, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("\nexpected: <%+v>, received: <%+v>", utils.OK, reply) + } + + if err := adms.GetDispatcherHost(context.Background(), arg, &result); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(result, *dspHost.DispatcherHost) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(dspHost.DispatcherHost), utils.ToJSON(result)) + } + + var dspHostIDs []string + expDspHostIDs := []string{"dspHost1"} + + if err := adms.GetDispatcherHostIDs(context.Background(), &utils.ArgsItemIDs{}, + &dspHostIDs); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(dspHostIDs, expDspHostIDs) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", expDspHostIDs, dspHostIDs) + } + + var rplyCount int + + if err := adms.GetDispatcherHostsCount(context.Background(), &utils.ArgsItemIDs{}, + &rplyCount); err != nil { + t.Error(err) + } else if rplyCount != len(dspHostIDs) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", len(dspHostIDs), rplyCount) + } + + if err := adms.RemoveDispatcherHost(context.Background(), arg, &reply); err != nil { + t.Error(err) + } + + engine.Cache.Clear(nil) + if err := adms.GetDispatcherHost(context.Background(), arg, &result); err == nil || + err != utils.ErrNotFound { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersGetDispatcherHostCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + var rcv engine.DispatcherHost + experr := "MANDATORY_IE_MISSING: [ID]" + + if err := adms.GetDispatcherHost(context.Background(), &utils.TenantIDWithAPIOpts{}, &rcv); err == nil || + err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + adms.dm = nil + experr = "SERVER_ERROR: NO_DATABASE_CONNECTION" + + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersGetDispatcherHostCheckErrors", + }, + } + + if err := adms.GetDispatcherHost(context.Background(), arg, &rcv); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersSetDispatcherHostCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + + dspHost := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + RemoteHost: &config.RemoteHost{}, + }, + } + + var reply string + experr := "MANDATORY_IE_MISSING: [ID]" + + if err := adms.SetDispatcherHost(context.Background(), dspHost, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dspHost.ID = "TestDispatchersSetDispatcherHostCheckErrors" + adms.connMgr = engine.NewConnManager(cfg) + adms.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), utils.CacheSv1, make(chan birpc.ClientConnector)) + ctx, cancel := context.WithTimeout(context.Background(), 10) + experr = "SERVER_ERROR: context deadline exceeded" + cfg.GeneralCfg().DefaultCaching = utils.MetaRemove + if err := adms.SetDispatcherHost(ctx, dspHost, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected <%+v>,\nreceived <%+v>", experr, err) + } + cancel() + + dbMock := &engine.DataDBMock{ + GetDispatcherHostDrvF: func(*context.Context, string, string) (*engine.DispatcherHost, error) { + dspHost := &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "TEST", + }, + } + return dspHost, nil + }, + SetDispatcherHostDrvF: func(*context.Context, *engine.DispatcherHost) error { + return nil + }, + RemoveDispatcherHostDrvF: func(*context.Context, string, string) error { + return nil + }, + GetKeysForPrefixF: func(c *context.Context, s string) ([]string, error) { + return nil, nil + }, + } + + adms.dm = engine.NewDataManager(dbMock, cfg.CacheCfg(), nil) + experr = "SERVER_ERROR: NOT_IMPLEMENTED" + + if err := adms.SetDispatcherHost(context.Background(), dspHost, &reply); err == nil || + err.Error() != experr { + t.Errorf("\nexpected <%+v>, \nreceived <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} + +func TestDispatchersRemoveDispatcherHostCheckErrors(t *testing.T) { + engine.Cache.Clear(nil) + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil) + adms := &AdminSv1{ + cfg: cfg, + dm: dm, + } + + dspPrf := &engine.DispatcherHostWithAPIOpts{ + DispatcherHost: &engine.DispatcherHost{ + RemoteHost: &config.RemoteHost{ + ID: "TestDispatchersRemoveDispatcherHostCheckErrors", + }, + Tenant: "cgrates.org", + }, + } + var reply string + + if err := adms.SetDispatcherHost(context.Background(), dspPrf, &reply); err != nil { + t.Error(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 10) + adms.cfg.GeneralCfg().DefaultCaching = "not_a_caching_type" + adms.connMgr = engine.NewConnManager(cfg) + adms.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), utils.CacheSv1, make(chan birpc.ClientConnector)) + experr := "SERVER_ERROR: context deadline exceeded" + + if err := adms.RemoveDispatcherHost(ctx, &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherHostCheckErrors", + }, + }, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + cancel() + + adms.cfg.GeneralCfg().DefaultCaching = utils.MetaNone + var rcv engine.DispatcherHost + + arg := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherHostCheckErrors", + }, + } + + if err := adms.GetDispatcherHost(context.Background(), arg, &rcv); err == nil || err != utils.ErrNotFound { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err) + } + + experr = "MANDATORY_IE_MISSING: [ID]" + + if err := adms.RemoveDispatcherHost(context.Background(), + &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{}}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected <%+v>, \nreceived: <%+v>", experr, err) + } + + adms.dm = nil + experr = "SERVER_ERROR: NO_DATABASE_CONNECTION" + + if err := adms.RemoveDispatcherHost(context.Background(), &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherHostCheckErrors", + }}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dbMock := &engine.DataDBMock{ + GetDispatcherHostDrvF: func(*context.Context, string, string) (*engine.DispatcherHost, error) { + dspPrf := &engine.DispatcherHost{ + Tenant: "cgrates.org", + RemoteHost: &config.RemoteHost{ + ID: "TEST", + }, + } + return dspPrf, nil + }, + SetDispatcherHostDrvF: func(*context.Context, *engine.DispatcherHost) error { + return nil + }, + RemoveDispatcherHostDrvF: func(*context.Context, string, string) error { + return nil + }, + GetKeysForPrefixF: func(c *context.Context, s string) ([]string, error) { + return nil, nil + }, + SetIndexesDrvF: func(ctx *context.Context, idxItmType, tntCtx string, indexes map[string]utils.StringSet, commit bool, transactionID string) (err error) { + return nil + }, + GetIndexesDrvF: func(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error) { + return map[string]utils.StringSet{}, nil + }, + } + + engine.Cache.Clear(nil) + adms.dm = engine.NewDataManager(dbMock, cfg.CacheCfg(), nil) + experr = "SERVER_ERROR: NOT_IMPLEMENTED" + + if err := adms.RemoveDispatcherHost(context.Background(), + &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + ID: "TestDispatchersRemoveDispatcherHostCheckErrors", + }}, &reply); err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + dm.DataDB().Flush(utils.EmptyString) +} diff --git a/apis/routes_test.go b/apis/routes_test.go index 729964b4d..01be322d5 100644 --- a/apis/routes_test.go +++ b/apis/routes_test.go @@ -20,6 +20,7 @@ package apis import ( "reflect" + "sort" "testing" "github.com/cgrates/birpc" @@ -481,3 +482,138 @@ func TestRoutesSv1Ping(t *testing.T) { t.Errorf("Unexpected reply error") } } + +func TestRoutesGetRouteProfilesOK(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, nil, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr) + args1 := &engine.RouteProfileWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + Sorting: utils.MetaWeight, + Routes: []*engine.Route{ + { + ID: "ROUTE1", + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + var setReply string + if err := admS.SetRouteProfile(context.Background(), args1, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + args2 := &engine.RouteProfileWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + Tenant: "cgrates.org", + ID: "test_ID2", + Sorting: utils.MetaWeight, + Routes: []*engine.Route{ + { + ID: "ROUTE2", + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetRouteProfile(context.Background(), args2, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + // this profile will not match + args3 := &engine.RouteProfileWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + Tenant: "cgrates.org", + ID: "test2_ID1", + Sorting: utils.MetaWeight, + Routes: []*engine.Route{ + { + ID: "ROUTE1", + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetRouteProfile(context.Background(), args3, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + argsGet := &utils.ArgsItemIDs{ + Tenant: "cgrates.org", + ItemsPrefix: "test_ID", + } + exp := []*engine.RouteProfile{ + { + Tenant: "cgrates.org", + ID: "test_ID1", + Sorting: utils.MetaWeight, + Routes: []*engine.Route{ + { + ID: "ROUTE1", + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + { + Tenant: "cgrates.org", + ID: "test_ID2", + Sorting: utils.MetaWeight, + Routes: []*engine.Route{ + { + ID: "ROUTE2", + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + } + + var getReply []*engine.RouteProfile + if err := admS.GetRouteProfiles(context.Background(), argsGet, &getReply); err != nil { + t.Error(err) + } else { + sort.Slice(getReply, func(i, j int) bool { + return getReply[i].ID < getReply[j].ID + }) + if !reflect.DeepEqual(getReply, exp) { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(getReply)) + } + } +} diff --git a/apis/stats_test.go b/apis/stats_test.go index 669ca339a..1ddae9536 100644 --- a/apis/stats_test.go +++ b/apis/stats_test.go @@ -752,3 +752,156 @@ func TestStatsAPIs(t *testing.T) { t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.OK, reply) } } + +func TestStatQueuesGetStatQueueProfilesOK(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, nil, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr) + args1 := &engine.StatQueueProfileWithAPIOpts{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + QueueLength: 10, + MinItems: 2, + ThresholdIDs: []string{utils.MetaNone}, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaACD, + }, + }, + Stored: true, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + var setReply string + if err := admS.SetStatQueueProfile(context.Background(), args1, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + args2 := &engine.StatQueueProfileWithAPIOpts{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "test_ID2", + QueueLength: 15, + MinItems: 3, + ThresholdIDs: []string{utils.MetaNone}, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaTCD, + }, + }, + Stored: false, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetStatQueueProfile(context.Background(), args2, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + // this profile will not match + args3 := &engine.StatQueueProfileWithAPIOpts{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "test2_ID1", + QueueLength: 10, + MinItems: 2, + ThresholdIDs: []string{utils.MetaNone}, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaACD, + }, + { + MetricID: utils.MetaTCD, + }, + }, + Stored: false, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetStatQueueProfile(context.Background(), args3, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + argsGet := &utils.ArgsItemIDs{ + Tenant: "cgrates.org", + ItemsPrefix: "test_ID", + } + exp := []*engine.StatQueueProfile{ + { + Tenant: "cgrates.org", + ID: "test_ID1", + QueueLength: 10, + MinItems: 2, + ThresholdIDs: []string{utils.MetaNone}, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaACD, + }, + }, + Stored: true, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + { + Tenant: "cgrates.org", + ID: "test_ID2", + QueueLength: 15, + MinItems: 3, + ThresholdIDs: []string{utils.MetaNone}, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaTCD, + }, + }, + Stored: false, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + } + + var getReply []*engine.StatQueueProfile + if err := admS.GetStatQueueProfiles(context.Background(), argsGet, &getReply); err != nil { + t.Error(err) + } else { + sort.Slice(getReply, func(i, j int) bool { + return getReply[i].ID < getReply[j].ID + }) + if !reflect.DeepEqual(getReply, exp) { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(getReply)) + } + } +} diff --git a/apis/thresholds_test.go b/apis/thresholds_test.go index 571c1b2f0..00cea506a 100644 --- a/apis/thresholds_test.go +++ b/apis/thresholds_test.go @@ -671,3 +671,123 @@ func TestThresholdsAPIs(t *testing.T) { t.Error(err) } } + +func TestThresholdsGetThresholdProfilesOK(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.GeneralCfg().DefaultCaching = utils.MetaNone + connMgr := engine.NewConnManager(cfg) + dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items) + dm := engine.NewDataManager(dataDB, nil, connMgr) + admS := NewAdminSv1(cfg, dm, connMgr) + args1 := &engine.ThresholdProfileWithAPIOpts{ + ThresholdProfile: &engine.ThresholdProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + MaxHits: 5, + MinHits: 1, + ActionProfileIDs: []string{utils.MetaNone}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + var setReply string + if err := admS.SetThresholdProfile(context.Background(), args1, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + args2 := &engine.ThresholdProfileWithAPIOpts{ + ThresholdProfile: &engine.ThresholdProfile{ + Tenant: "cgrates.org", + ID: "test_ID2", + MaxHits: 4, + MinHits: 2, + ActionProfileIDs: []string{utils.MetaNone}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetThresholdProfile(context.Background(), args2, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + // this profile will not match + args3 := &engine.ThresholdProfileWithAPIOpts{ + ThresholdProfile: &engine.ThresholdProfile{ + Tenant: "cgrates.org", + ID: "test2_ID1", + MaxHits: 5, + MinHits: 1, + ActionProfileIDs: []string{utils.MetaNone}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + + if err := admS.SetThresholdProfile(context.Background(), args3, &setReply); err != nil { + t.Error(err) + } else if setReply != "OK" { + t.Error("Unexpected reply returned:", setReply) + } + + argsGet := &utils.ArgsItemIDs{ + Tenant: "cgrates.org", + ItemsPrefix: "test_ID", + } + exp := []*engine.ThresholdProfile{ + { + Tenant: "cgrates.org", + ID: "test_ID1", + MaxHits: 5, + MinHits: 1, + ActionProfileIDs: []string{utils.MetaNone}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + { + Tenant: "cgrates.org", + ID: "test_ID2", + MaxHits: 4, + MinHits: 2, + ActionProfileIDs: []string{utils.MetaNone}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + } + + var getReply []*engine.ThresholdProfile + if err := admS.GetThresholdProfiles(context.Background(), argsGet, &getReply); err != nil { + t.Error(err) + } else { + sort.Slice(getReply, func(i, j int) bool { + return getReply[i].ID < getReply[j].ID + }) + if !reflect.DeepEqual(getReply, exp) { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(getReply)) + } + } +} diff --git a/engine/datadbmock.go b/engine/datadbmock.go index a36d2b71c..2b933e28d 100644 --- a/engine/datadbmock.go +++ b/engine/datadbmock.go @@ -24,46 +24,52 @@ import ( ) type DataDBMock struct { - RemoveRateProfileDrvF func(ctx *context.Context, str1 string, str2 string, rateIDs *[]string) error - SetRateProfileDrvF func(*context.Context, *utils.RateProfile) error - GetRateProfileDrvF func(*context.Context, string, string) (*utils.RateProfile, error) - GetRateProfileRatesDrvF func(*context.Context, string, string, string, bool) ([]string, []*utils.Rate, error) - GetKeysForPrefixF func(*context.Context, string) ([]string, error) - GetIndexesDrvF func(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error) - SetIndexesDrvF func(ctx *context.Context, idxItmType, tntCtx string, indexes map[string]utils.StringSet, commit bool, transactionID string) (err error) - GetAttributeProfileDrvF func(ctx *context.Context, str1 string, str2 string) (*AttributeProfile, error) - SetAttributeProfileDrvF func(ctx *context.Context, attr *AttributeProfile) error - RemoveAttributeProfileDrvF func(ctx *context.Context, str1 string, str2 string) error - SetLoadIDsDrvF func(ctx *context.Context, loadIDs map[string]int64) error - GetFilterDrvF func(ctx *context.Context, str1 string, str2 string) (*Filter, error) - GetChargerProfileDrvF func(ctx *context.Context, tnt, id string) (*ChargerProfile, error) - SetChargerProfileDrvF func(ctx *context.Context, chr *ChargerProfile) (err error) - GetThresholdProfileDrvF func(ctx *context.Context, tenant, id string) (tp *ThresholdProfile, err error) - SetThresholdProfileDrvF func(ctx *context.Context, tp *ThresholdProfile) (err error) - RemThresholdProfileDrvF func(ctx *context.Context, tenant, id string) (err error) - GetThresholdDrvF func(ctx *context.Context, tenant, id string) (*Threshold, error) - RemoveThresholdDrvF func(ctx *context.Context, tnt, id string) error - GetResourceProfileDrvF func(ctx *context.Context, tnt, id string) (*ResourceProfile, error) - SetResourceProfileDrvF func(ctx *context.Context, rp *ResourceProfile) error - RemoveResourceProfileDrvF func(ctx *context.Context, tnt, id string) error - RemoveResourceDrvF func(ctx *context.Context, tnt, id string) error - SetResourceDrvF func(ctx *context.Context, r *Resource) error - GetStatQueueProfileDrvF func(ctx *context.Context, tenant, id string) (sq *StatQueueProfile, err error) - SetStatQueueProfileDrvF func(ctx *context.Context, sq *StatQueueProfile) (err error) - RemStatQueueProfileDrvF func(ctx *context.Context, tenant, id string) (err error) - RemStatQueueDrvF func(ctx *context.Context, tenant, id string) (err error) - SetFilterDrvF func(ctx *context.Context, fltr *Filter) error - GetActionProfileDrvF func(ctx *context.Context, tenant string, ID string) (*ActionProfile, error) - SetActionProfileDrvF func(ctx *context.Context, ap *ActionProfile) error - RemoveActionProfileDrvF func(ctx *context.Context, tenant string, ID string) error - RemoveFilterDrvF func(ctx *context.Context, str1 string, str2 string) error - SetAccountDrvF func(ctx *context.Context, profile *utils.Account) error - GetAccountDrvF func(ctx *context.Context, str1 string, str2 string) (*utils.Account, error) - RemoveAccountDrvF func(ctx *context.Context, str1 string, str2 string) error - GetRouteProfileDrvF func(ctx *context.Context, tnt, id string) (*RouteProfile, error) - SetRouteProfileDrvF func(ctx *context.Context, rtPrf *RouteProfile) error - RemoveRouteProfileDrvF func(ctx *context.Context, tnt, id string) error - RemoveChargerProfileDrvF func(ctx *context.Context, chr string, rpl string) error + RemoveRateProfileDrvF func(ctx *context.Context, str1 string, str2 string, rateIDs *[]string) error + SetRateProfileDrvF func(*context.Context, *utils.RateProfile) error + GetRateProfileDrvF func(*context.Context, string, string) (*utils.RateProfile, error) + GetRateProfileRatesDrvF func(*context.Context, string, string, string, bool) ([]string, []*utils.Rate, error) + GetKeysForPrefixF func(*context.Context, string) ([]string, error) + GetIndexesDrvF func(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error) + SetIndexesDrvF func(ctx *context.Context, idxItmType, tntCtx string, indexes map[string]utils.StringSet, commit bool, transactionID string) (err error) + GetAttributeProfileDrvF func(ctx *context.Context, str1 string, str2 string) (*AttributeProfile, error) + SetAttributeProfileDrvF func(ctx *context.Context, attr *AttributeProfile) error + RemoveAttributeProfileDrvF func(ctx *context.Context, str1 string, str2 string) error + SetLoadIDsDrvF func(ctx *context.Context, loadIDs map[string]int64) error + GetFilterDrvF func(ctx *context.Context, str1 string, str2 string) (*Filter, error) + GetChargerProfileDrvF func(ctx *context.Context, tnt, id string) (*ChargerProfile, error) + SetChargerProfileDrvF func(ctx *context.Context, chr *ChargerProfile) (err error) + GetThresholdProfileDrvF func(ctx *context.Context, tenant, id string) (tp *ThresholdProfile, err error) + SetThresholdProfileDrvF func(ctx *context.Context, tp *ThresholdProfile) (err error) + RemThresholdProfileDrvF func(ctx *context.Context, tenant, id string) (err error) + GetThresholdDrvF func(ctx *context.Context, tenant, id string) (*Threshold, error) + RemoveThresholdDrvF func(ctx *context.Context, tnt, id string) error + GetResourceProfileDrvF func(ctx *context.Context, tnt, id string) (*ResourceProfile, error) + SetResourceProfileDrvF func(ctx *context.Context, rp *ResourceProfile) error + RemoveResourceProfileDrvF func(ctx *context.Context, tnt, id string) error + RemoveResourceDrvF func(ctx *context.Context, tnt, id string) error + SetResourceDrvF func(ctx *context.Context, r *Resource) error + GetStatQueueProfileDrvF func(ctx *context.Context, tenant, id string) (sq *StatQueueProfile, err error) + SetStatQueueProfileDrvF func(ctx *context.Context, sq *StatQueueProfile) (err error) + RemStatQueueProfileDrvF func(ctx *context.Context, tenant, id string) (err error) + RemStatQueueDrvF func(ctx *context.Context, tenant, id string) (err error) + SetFilterDrvF func(ctx *context.Context, fltr *Filter) error + GetActionProfileDrvF func(ctx *context.Context, tenant string, ID string) (*ActionProfile, error) + SetActionProfileDrvF func(ctx *context.Context, ap *ActionProfile) error + RemoveActionProfileDrvF func(ctx *context.Context, tenant string, ID string) error + RemoveFilterDrvF func(ctx *context.Context, str1 string, str2 string) error + SetAccountDrvF func(ctx *context.Context, profile *utils.Account) error + GetAccountDrvF func(ctx *context.Context, str1 string, str2 string) (*utils.Account, error) + RemoveAccountDrvF func(ctx *context.Context, str1 string, str2 string) error + GetRouteProfileDrvF func(ctx *context.Context, tnt, id string) (*RouteProfile, error) + SetRouteProfileDrvF func(ctx *context.Context, rtPrf *RouteProfile) error + RemoveRouteProfileDrvF func(ctx *context.Context, tnt, id string) error + RemoveChargerProfileDrvF func(ctx *context.Context, chr string, rpl string) error + GetDispatcherProfileDrvF func(*context.Context, string, string) (*DispatcherProfile, error) + SetDispatcherProfileDrvF func(*context.Context, *DispatcherProfile) error + RemoveDispatcherProfileDrvF func(*context.Context, string, string) error + GetDispatcherHostDrvF func(*context.Context, string, string) (*DispatcherHost, error) + SetDispatcherHostDrvF func(*context.Context, *DispatcherHost) error + RemoveDispatcherHostDrvF func(*context.Context, string, string) error } //Storage methods @@ -330,15 +336,24 @@ func (dbM *DataDBMock) RemoveChargerProfileDrv(ctx *context.Context, chr string, return utils.ErrNotImplemented } -func (dbM *DataDBMock) GetDispatcherProfileDrv(*context.Context, string, string) (*DispatcherProfile, error) { +func (dbM *DataDBMock) GetDispatcherProfileDrv(ctx *context.Context, tnt, id string) (*DispatcherProfile, error) { + if dbM.GetDispatcherProfileDrvF != nil { + return dbM.GetDispatcherProfileDrvF(ctx, tnt, id) + } return nil, utils.ErrNotImplemented } -func (dbM *DataDBMock) SetDispatcherProfileDrv(*context.Context, *DispatcherProfile) error { +func (dbM *DataDBMock) SetDispatcherProfileDrv(ctx *context.Context, dP *DispatcherProfile) error { + if dbM.GetDispatcherProfileDrvF != nil { + return dbM.SetDispatcherProfileDrvF(ctx, dP) + } return utils.ErrNotImplemented } -func (dbM *DataDBMock) RemoveDispatcherProfileDrv(*context.Context, string, string) error { +func (dbM *DataDBMock) RemoveDispatcherProfileDrv(ctx *context.Context, tnt, id string) error { + if dbM.RemoveDispatcherProfileDrvF != nil { + return dbM.RemoveDispatcherProfileDrvF(ctx, tnt, id) + } return utils.ErrNotImplemented } @@ -357,15 +372,24 @@ func (dbM *DataDBMock) RemoveLoadIDsDrv() error { return utils.ErrNotImplemented } -func (dbM *DataDBMock) GetDispatcherHostDrv(*context.Context, string, string) (*DispatcherHost, error) { +func (dbM *DataDBMock) GetDispatcherHostDrv(ctx *context.Context, tnt, id string) (*DispatcherHost, error) { + if dbM.GetDispatcherHostDrvF != nil { + return dbM.GetDispatcherHostDrvF(ctx, tnt, id) + } return nil, utils.ErrNotImplemented } -func (dbM *DataDBMock) SetDispatcherHostDrv(*context.Context, *DispatcherHost) error { +func (dbM *DataDBMock) SetDispatcherHostDrv(ctx *context.Context, dH *DispatcherHost) error { + if dbM.GetDispatcherHostDrvF != nil { + return dbM.SetDispatcherHostDrvF(ctx, dH) + } return utils.ErrNotImplemented } -func (dbM *DataDBMock) RemoveDispatcherHostDrv(*context.Context, string, string) error { +func (dbM *DataDBMock) RemoveDispatcherHostDrv(ctx *context.Context, tnt, id string) error { + if dbM.RemoveDispatcherHostDrvF != nil { + return dbM.RemoveDispatcherHostDrvF(ctx, tnt, id) + } return utils.ErrNotImplemented }