diff --git a/apis/chargers_test.go b/apis/chargers_test.go
index 63a9be83c..d9afbdb2e 100644
--- a/apis/chargers_test.go
+++ b/apis/chargers_test.go
@@ -19,10 +19,12 @@ along with this program. If not, see
package apis
import (
+ "fmt"
"reflect"
"sort"
"testing"
+ "github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -1095,3 +1097,234 @@ func TestChargersGetChargerProfileCheckErrors(t *testing.T) {
dm.DataDB().Flush(utils.EmptyString)
}
+
+func TestChargersNewChargerSv1(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ dataDB := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil)
+ chS := engine.NewChargerService(dm, nil, cfg, nil)
+
+ exp := &ChargerSv1{
+ cS: chS,
+ }
+ rcv := NewChargerSv1(chS)
+
+ if !reflect.DeepEqual(rcv, exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
+ }
+}
+
+func TestChargersAPIs(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ cfg.ChargerSCfg().AttributeSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
+ cfg.AttributeSCfg().Opts.ProcessRuns = []*utils.DynamicIntOpt{
+ {
+ Value: 2,
+ },
+ }
+ data := engine.NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+
+ expEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventTest",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsAttributesProfileIDs: []string{"ATTR1", "ATTR2"},
+ utils.MetaChargeID: "",
+ utils.OptsContext: utils.MetaChargers,
+ utils.Subsys: utils.MetaChargers,
+ utils.MetaRunID: "run_1",
+ },
+ }
+
+ mCC := &mockClientConn{
+ calls: map[string]func(*context.Context, interface{}, interface{}) error{
+ utils.AttributeSv1ProcessEvent: func(ctx *context.Context, args, reply interface{}) error {
+ expEv.APIOpts[utils.MetaChargeID] = args.(*utils.CGREvent).APIOpts[utils.MetaChargeID]
+ if !reflect.DeepEqual(args, expEv) {
+ return fmt.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(expEv), utils.ToJSON(args))
+ }
+ return nil
+ },
+ },
+ }
+ rpcInternal := make(chan birpc.ClientConnector, 1)
+ rpcInternal <- mCC
+ cM := engine.NewConnManager(cfg)
+ cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes), utils.AttributeSv1, rpcInternal)
+
+ adms := &AdminSv1{
+ dm: dm,
+ cfg: cfg,
+ }
+
+ argsCharger1 := &ChargerWithAPIOpts{
+ ChargerProfile: &engine.ChargerProfile{
+ Tenant: "cgrates.org",
+ ID: "CHARGER1",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ },
+ },
+ RunID: "run_1",
+ AttributeIDs: []string{"ATTR1", "ATTR2"},
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ },
+ APIOpts: nil,
+ }
+
+ var setReply string
+ if err := adms.SetChargerProfile(context.Background(), argsCharger1, &setReply); err != nil {
+ t.Error(err)
+ } else if setReply != "OK" {
+ t.Error("Unexpected reply returned:", setReply)
+ }
+
+ argsCharger2 := &ChargerWithAPIOpts{
+ ChargerProfile: &engine.ChargerProfile{
+ Tenant: "cgrates.org",
+ ID: "CHARGER2",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 20,
+ },
+ },
+ RunID: "run_2",
+ AttributeIDs: []string{"ATTR3"},
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ },
+ APIOpts: nil,
+ }
+
+ if err := adms.SetChargerProfile(context.Background(), argsCharger2, &setReply); err != nil {
+ t.Error(err)
+ } else if setReply != "OK" {
+ t.Error("Unexpected reply returned:", setReply)
+ }
+
+ cS := engine.NewChargerService(dm, fltrs, cfg, cM)
+ cSv1 := NewChargerSv1(cS)
+
+ argsGetForEvent := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventTest",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]interface{}{},
+ }
+ exp := engine.ChargerProfiles{
+ {
+
+ Tenant: "cgrates.org",
+ ID: "CHARGER2",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 20,
+ },
+ },
+ RunID: "run_2",
+ AttributeIDs: []string{"ATTR3"},
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ },
+ {
+ Tenant: "cgrates.org",
+ ID: "CHARGER1",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ },
+ },
+ RunID: "run_1",
+ AttributeIDs: []string{"ATTR1", "ATTR2"},
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ },
+ }
+ var reply engine.ChargerProfiles
+ if err := cSv1.GetChargersForEvent(context.Background(), argsGetForEvent, &reply); err != nil {
+ t.Error(err)
+ } else {
+ if utils.ToJSON(reply) != utils.ToJSON(exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(reply))
+ }
+ }
+
+ argsCharger2 = &ChargerWithAPIOpts{
+ ChargerProfile: &engine.ChargerProfile{
+ Tenant: "cgrates.org",
+ ID: "CHARGER2",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 20,
+ },
+ },
+ RunID: "run_2",
+ AttributeIDs: []string{"ATTR3"},
+ FilterIDs: []string{"*string:~*req.Account:1002"},
+ },
+ APIOpts: nil,
+ }
+
+ if err := adms.SetChargerProfile(context.Background(), argsCharger2, &setReply); err != nil {
+ t.Error(err)
+ } else if setReply != "OK" {
+ t.Error("Unexpected reply returned:", setReply)
+ }
+
+ argsProcessEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventTest",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]interface{}{},
+ }
+ expProcessEv := []*engine.ChrgSProcessEventReply{
+ {
+ ChargerSProfile: "CHARGER1",
+ AlteredFields: []string{"*opts.*runID", "*opts.*chargeID"},
+ CGREvent: &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventTest",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsAttributesProfileIDs: []string{"ATTR1", "ATTR2"},
+ utils.MetaChargeID: "",
+ utils.OptsContext: utils.MetaChargers,
+ utils.Subsys: utils.MetaChargers,
+ utils.MetaRunID: "run_1",
+ },
+ },
+ },
+ }
+ var replyProcessEv []*engine.ChrgSProcessEventReply
+ if err := cSv1.ProcessEvent(context.Background(), argsProcessEv, &replyProcessEv); err != nil {
+ t.Error(err)
+ } else {
+ expProcessEv[0].CGREvent.APIOpts[utils.MetaChargeID] = replyProcessEv[0].CGREvent.APIOpts[utils.MetaChargeID]
+ if !reflect.DeepEqual(replyProcessEv, expProcessEv) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(expProcessEv), utils.ToJSON(replyProcessEv))
+ }
+ }
+}
+
+func TestChargersSv1Ping(t *testing.T) {
+ cSv1 := new(ChargerSv1)
+ var reply string
+ if err := cSv1.Ping(nil, nil, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.Pong {
+ t.Errorf("Unexpected reply error")
+ }
+}
diff --git a/apis/dispatchers_test.go b/apis/dispatchers_test.go
index aa00424e6..5e9c8870b 100644
--- a/apis/dispatchers_test.go
+++ b/apis/dispatchers_test.go
@@ -1429,3 +1429,29 @@ func TestDispatchersGetDispatcherHostsGetHostErr(t *testing.T) {
dm.DataDB().Flush(utils.EmptyString)
}
+
+func TestDispatchersSetDispatcherHostErr(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ adms := &AdminSv1{
+ cfg: cfg,
+ }
+
+ dspHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ RemoteHost: &config.RemoteHost{
+ ID: "TEST",
+ },
+ },
+ }
+
+ var reply string
+ experr := "SERVER_ERROR: NO_DATABASE_CONNECTION"
+
+ if err := adms.SetDispatcherHost(context.Background(), dspHost, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+}
diff --git a/apis/rates_test.go b/apis/rates_test.go
index e65262062..b5f49dd30 100644
--- a/apis/rates_test.go
+++ b/apis/rates_test.go
@@ -2317,3 +2317,192 @@ func TestRatesGetRateProfileRatesCountErrMissing(t *testing.T) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
}
}
+
+func TestRatesGetRateProfileRateIDsErrNotFound(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+
+ dm := engine.NewDataManager(engine.NewInternalDB(nil, nil, nil), cfg.CacheCfg(), nil)
+ adms := &AdminSv1{
+ cfg: cfg,
+ dm: dm,
+ }
+
+ var reply []string
+
+ if err := adms.GetRateProfileRateIDs(context.Background(),
+ &utils.ArgsSubItemIDs{
+ Tenant: "cgrates.org",
+ ProfileID: "prfID",
+ }, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestRatesGetRateProfileRateIDsErrKeys(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ dbMock := &engine.DataDBMock{
+ GetRateProfileRatesDrvF: func(ctx *context.Context, s1, s2, s3 string, b bool) ([]string, []*utils.Rate, error) {
+ return []string{}, nil, nil
+ },
+ }
+ dm := engine.NewDataManager(dbMock, cfg.CacheCfg(), nil)
+ adms := &AdminSv1{
+ cfg: cfg,
+ dm: dm,
+ }
+
+ var reply []string
+
+ if err := adms.GetRateProfileRateIDs(context.Background(),
+ &utils.ArgsSubItemIDs{
+ Tenant: "cgrates.org",
+ ProfileID: "prfID",
+ }, &reply); err == nil || err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestRatesGetRateProfileRateIDsGetOptsErr(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ dbMock := &engine.DataDBMock{
+ GetRateProfileRatesDrvF: func(ctx *context.Context, s1, s2, s3 string, b bool) ([]string, []*utils.Rate, error) {
+ return []string{"RATE1", "RATE2"}, []*utils.Rate{
+ {
+ ID: "RATE1",
+ },
+ {
+ ID: "RATE2",
+ },
+ }, nil
+ },
+ }
+
+ dm := engine.NewDataManager(dbMock, cfg.CacheCfg(), nil)
+ adms := &AdminSv1{
+ cfg: cfg,
+ dm: dm,
+ }
+
+ var reply []string
+ experr := "cannot convert field: true to int"
+
+ if err := adms.GetRateProfileRateIDs(context.Background(),
+ &utils.ArgsSubItemIDs{
+ Tenant: "cgrates.org",
+ ProfileID: "prfID",
+ APIOpts: map[string]interface{}{
+ utils.PageLimitOpt: true,
+ },
+ }, &reply); err == nil || err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestRatesGetRateProfileRateIDsPaginateErr(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ dbMock := &engine.DataDBMock{
+ GetRateProfileRatesDrvF: func(ctx *context.Context, s1, s2, s3 string, b bool) ([]string, []*utils.Rate, error) {
+ return []string{"RATE1", "RATE2"}, []*utils.Rate{
+ {
+ ID: "RATE1",
+ },
+ {
+ ID: "RATE2",
+ },
+ }, nil
+ },
+ }
+
+ dm := engine.NewDataManager(dbMock, cfg.CacheCfg(), nil)
+ adms := &AdminSv1{
+ cfg: cfg,
+ dm: dm,
+ }
+
+ var reply []string
+ experr := `SERVER_ERROR: maximum number of items exceeded`
+
+ if err := adms.GetRateProfileRateIDs(context.Background(),
+ &utils.ArgsSubItemIDs{
+ ProfileID: "prfID",
+ APIOpts: map[string]interface{}{
+ utils.PageLimitOpt: 2,
+ utils.PageOffsetOpt: 4,
+ utils.PageMaxItemsOpt: 5,
+ },
+ }, &reply); err == nil || err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestRatesGetRateProfileRateIDsErrMissing(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.GeneralCfg().DefaultCaching = utils.MetaNone
+ dataDB := engine.NewInternalDB(nil, nil, nil)
+ dm := engine.NewDataManager(dataDB, cfg.CacheCfg(), nil)
+ adms := &AdminSv1{
+ cfg: cfg,
+ dm: dm,
+ }
+
+ var reply []string
+ experr := `MANDATORY_IE_MISSING: [ProfileID]`
+
+ if err := adms.GetRateProfileRateIDs(context.Background(),
+ &utils.ArgsSubItemIDs{
+ Tenant: "cgrates.org",
+ }, &reply); err == nil || err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestRatesSetRateProfileErrConvertOverwriteOpt(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, nil, connMgr)
+ admS := NewAdminSv1(cfg, dm, connMgr)
+ args := &utils.APIRateProfile{
+ RateProfile: &utils.RateProfile{
+ Tenant: "cgrates.org",
+ FilterIDs: []string{"*string:~*req.Subject:1001"},
+ Rates: map[string]*utils.Rate{
+ "RT_WEEK": {
+ ID: "RT_WEEK",
+ ActivationTimes: "* * * * *",
+ },
+ },
+ ID: "RateProfile",
+ },
+ APIOpts: map[string]interface{}{
+ utils.MetaRateSOverwrite: "invalid_opt",
+ },
+ }
+ expected := `strconv.ParseBool: parsing "invalid_opt": invalid syntax`
+ var rtRply string
+ err := admS.SetRateProfile(context.Background(), args, &rtRply)
+ if err == nil || err.Error() != expected {
+ t.Errorf("expected <%+v>, \nreceived <%+v>", expected, err)
+ }
+}