diff --git a/engine/chargers_test.go b/engine/chargers_test.go index f97f65245..2be99fad1 100644 --- a/engine/chargers_test.go +++ b/engine/chargers_test.go @@ -629,3 +629,45 @@ func TestChargersmatchingChargerProfilesForEventErrGetChPrf(t *testing.T) { } } + +func TestChargersprocessEvent(t *testing.T) { + defaultCfg := config.NewDefaultCGRConfig() + cS := &ChargerService{ + cfg: defaultCfg, + } + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + APIOpts: map[string]interface{}{ + utils.OptsAttributesProcessRuns: 2, + }, + } + + experr := utils.ErrNotFound + rcv, err := cS.processEvent(cgrEv.Tenant, cgrEv) + + if err == nil || err != experr { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + if rcv != nil { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv) + } +} + +func TestChargersV1ProcessEventMissingArgs(t *testing.T) { + cS := &ChargerService{} + args := &utils.CGREvent{} + var reply *[]*ChrgSProcessEventReply + + experr := "MANDATORY_IE_MISSING: [Event]" + err := cS.V1ProcessEvent(args, reply) + + if err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } +} + +// func TestChargersShutdown(t *testing.T) { +// cS := &ChargerService{} +// cS.Shutdown() +// } diff --git a/engine/z_chargers_test.go b/engine/z_chargers_test.go index a8c5bfe3c..cf966aed4 100644 --- a/engine/z_chargers_test.go +++ b/engine/z_chargers_test.go @@ -16,11 +16,14 @@ along with this program. If not, see package engine import ( + "fmt" + "reflect" "testing" "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" + "github.com/cgrates/rpcclient" ) func TestChargersmatchingChargerProfilesForEventErrPass(t *testing.T) { @@ -141,3 +144,586 @@ func TestChargersmatchingChargerProfilesForEventNotActive(t *testing.T) { t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv) } } + +func TestChargersprocessEventNoConnIDs(t *testing.T) { + Cache.Clear(nil) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + + dbm := &DataDBMock{ + GetChargerProfileDrvF: func(s1, s2 string) (*ChargerProfile, error) { + return &ChargerProfile{ + Tenant: s1, + ID: s2, + RunID: utils.MetaDefault, + FilterIDs: []string{"fltr1"}, + }, nil + }, + GetKeysForPrefixF: func(s string) ([]string, error) { + return []string{s + "cgrates.org:chr1"}, nil + }, + GetFilterDrvF: func(s1, s2 string) (*Filter, error) { + return &Filter{ + Tenant: s1, + ID: s2, + }, nil + }, + } + dmFilter := NewDataManager(dbm, defaultCfg.CacheCfg(), nil) + cS := &ChargerService{ + dm: dmFilter, + filterS: &FilterS{ + dm: dmFilter, + cfg: defaultCfg, + }, + cfg: defaultCfg, + } + cgrEvTm := time.Date(2021, 4, 19, 12, 0, 0, 0, time.UTC) + cgrEv := &utils.CGREvent{ + Tenant: config.CgrConfig().GeneralCfg().DefaultTenant, + ID: "cgrEvID", + Event: map[string]interface{}{ + "Charger": "ChargerProfile1", + utils.AnswerTime: time.Date(2021, 4, 19, 12, 0, 0, 0, time.UTC), + "UsageInterval": "10s", + utils.Weight: "10.0", + }, + APIOpts: map[string]interface{}{ + utils.Subsys: utils.MetaChargers, + utils.OptsAttributesProcessRuns: 2, + }, + Time: &cgrEvTm, + } + + experr := fmt.Sprintf("MANDATORY_IE_MISSING: [%s]", "connIDs") + rcv, err := cS.processEvent(cgrEv.Tenant, cgrEv) + + if err == nil || err.Error() != experr { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + if rcv != nil { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv) + } + +} + +type ccMock struct { + calls map[string]func(args interface{}, reply interface{}) error +} + +func (ccM *ccMock) Call(serviceMethod string, args interface{}, reply interface{}) (err error) { + if call, has := ccM.calls[serviceMethod]; !has { + return rpcclient.ErrUnsupporteServiceMethod + } else { + return call(args, reply) + } +} + +func TestChargersprocessEventCallNilErr(t *testing.T) { + Cache.Clear(nil) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + + data := NewInternalDB(nil, nil, true) + dm := NewDataManager(data, defaultCfg.CacheCfg(), nil) + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + ccM := &ccMock{ + calls: map[string]func(args interface{}, reply interface{}) error{ + utils.AttributeSv1ProcessEvent: func(args, reply interface{}) error { + rply := AttrSProcessEventReply{ + AlteredFields: []string{utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + } + *reply.(*AttrSProcessEventReply) = rply + return nil + }, + }, + } + rpcInternal := make(chan rpcclient.ClientConnector, 1) + rpcInternal <- ccM + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + connMgr: NewConnManager(defaultCfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): rpcInternal, + }), + } + + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + + exp := []*ChrgSProcessEventReply{ + { + ChargerSProfile: "1001", + AlteredFields: []string{utils.MetaReqRunID, utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + }, + } + rcv, err := cS.processEvent(cgrEv.Tenant, cgrEv) + + if err != nil { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err) + } + + if !reflect.DeepEqual(exp, rcv) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(rcv)) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } + +} + +func TestChargersprocessEventCallErr(t *testing.T) { + Cache.Clear(nil) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + + data := NewInternalDB(nil, nil, true) + dm := NewDataManager(data, defaultCfg.CacheCfg(), nil) + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + ccM := &ccMock{ + calls: map[string]func(args interface{}, reply interface{}) error{ + utils.AttributeSv1ProcessEvent: func(args, reply interface{}) error { + return utils.ErrNotFound + }, + }, + } + rpcInternal := make(chan rpcclient.ClientConnector, 1) + rpcInternal <- ccM + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + connMgr: NewConnManager(defaultCfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): rpcInternal, + }), + } + + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + + exp := []*ChrgSProcessEventReply{ + { + ChargerSProfile: "1001", + AlteredFields: []string{utils.MetaReqRunID}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + "RunID": utils.MetaDefault, + }, + APIOpts: map[string]interface{}{ + utils.Subsys: utils.MetaChargers, + }, + }, + }, + } + rcv, err := cS.processEvent(cgrEv.Tenant, cgrEv) + + if err != nil { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err) + } + + if !reflect.DeepEqual(exp, rcv) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(rcv)) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } +} + +func TestChargersV1ProcessEventErrNotFound(t *testing.T) { + Cache.Clear(nil) + dataDB := NewInternalDB(nil, nil, true) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + dm := NewDataManager(dataDB, defaultCfg.CacheCfg(), nil) + + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + ccM := &ccMock{ + calls: map[string]func(args interface{}, reply interface{}) error{ + utils.AttributeSv1ProcessEvent: func(args, reply interface{}) error { + rply := AttrSProcessEventReply{ + AlteredFields: []string{utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + } + *reply.(*AttrSProcessEventReply) = rply + return nil + }, + }, + } + rpcInternal := make(chan rpcclient.ClientConnector, 1) + rpcInternal <- ccM + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + connMgr: NewConnManager(defaultCfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): rpcInternal, + }), + } + args := &utils.CGREvent{ + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1002", + }, + } + reply := &[]*ChrgSProcessEventReply{} + + experr := utils.ErrNotFound + err := cS.V1ProcessEvent(args, reply) + + if err == nil || err != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } +} + +func TestChargersV1ProcessEventErrOther(t *testing.T) { + Cache.Clear(nil) + dataDB := NewInternalDB(nil, nil, true) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + dm := NewDataManager(dataDB, defaultCfg.CacheCfg(), nil) + + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + ccM := &ccMock{ + calls: map[string]func(args interface{}, reply interface{}) error{ + "invalidMethod": func(args, reply interface{}) error { + rply := AttrSProcessEventReply{ + AlteredFields: []string{utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + } + *reply.(*AttrSProcessEventReply) = rply + return nil + }, + }, + } + rpcInternal := make(chan rpcclient.ClientConnector, 1) + rpcInternal <- ccM + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + connMgr: NewConnManager(defaultCfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): rpcInternal, + }), + } + args := &utils.CGREvent{ + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + reply := &[]*ChrgSProcessEventReply{} + + exp := &[]*ChrgSProcessEventReply{} + experr := fmt.Sprintf("SERVER_ERROR: %s", rpcclient.ErrUnsupporteServiceMethod) + err := cS.V1ProcessEvent(args, reply) + + if err == nil || err.Error() != experr { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + if !reflect.DeepEqual(reply, exp) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(reply)) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } +} + +func TestChargersV1ProcessEvent(t *testing.T) { + Cache.Clear(nil) + dataDB := NewInternalDB(nil, nil, true) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + dm := NewDataManager(dataDB, defaultCfg.CacheCfg(), nil) + + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + ccM := &ccMock{ + calls: map[string]func(args interface{}, reply interface{}) error{ + utils.AttributeSv1ProcessEvent: func(args, reply interface{}) error { + rply := AttrSProcessEventReply{ + AlteredFields: []string{utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + } + *reply.(*AttrSProcessEventReply) = rply + return nil + }, + }, + } + rpcInternal := make(chan rpcclient.ClientConnector, 1) + rpcInternal <- ccM + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + connMgr: NewConnManager(defaultCfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): rpcInternal, + }), + } + args := &utils.CGREvent{ + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + reply := &[]*ChrgSProcessEventReply{} + + exp := &[]*ChrgSProcessEventReply{ + { + ChargerSProfile: "1001", + AlteredFields: []string{utils.MetaReqRunID, utils.AccountField}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + }, + }, + } + err := cS.V1ProcessEvent(args, reply) + + if err != nil { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err) + } + + if !reflect.DeepEqual(reply, exp) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(reply)) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } +} + +func TestChargersV1GetChargersForEventNilErr(t *testing.T) { + Cache.Clear(nil) + dataDB := NewInternalDB(nil, nil, true) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + defaultCfg.ChargerSCfg().AttributeSConns = []string{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)} + dm := NewDataManager(dataDB, defaultCfg.CacheCfg(), nil) + + cP := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "1001", + RunID: utils.MetaDefault, + FilterIDs: []string{"*string:~*req.Account:1001"}, + } + if err := dm.SetChargerProfile(cP, true); err != nil { + t.Fatal(err) + } + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + } + args := &utils.CGREvent{ + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + reply := &ChargerProfiles{} + + exp := &ChargerProfiles{ + { + Tenant: "cgrates.org", + ID: "1001", + FilterIDs: []string{"*string:~*req.Account:1001"}, + RunID: "*default", + }, + } + err := cS.V1GetChargersForEvent(args, reply) + + if err != nil { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err) + } + + if !reflect.DeepEqual(reply, exp) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(reply)) + } + + if err := dm.DataDB().Flush(""); err != nil { + t.Error(err) + } +} + +func TestChargersV1GetChargersForEventErr(t *testing.T) { + Cache.Clear(nil) + defaultCfg := config.NewDefaultCGRConfig() + defaultCfg.ChargerSCfg().IndexedSelects = false + + dbm := &DataDBMock{ + GetKeysForPrefixF: func(s string) ([]string, error) { + return []string{":"}, nil + }, + } + dm := NewDataManager(dbm, defaultCfg.CacheCfg(), nil) + + cS := &ChargerService{ + dm: dm, + filterS: &FilterS{ + dm: dm, + cfg: defaultCfg, + }, + cfg: defaultCfg, + } + args := &utils.CGREvent{ + ID: "cgrEvID", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + reply := &ChargerProfiles{} + + exp := &ChargerProfiles{} + experr := fmt.Sprintf("SERVER_ERROR: %s", utils.ErrNotImplemented) + err := cS.V1GetChargersForEvent(args, reply) + + if err == nil || err.Error() != experr { + t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err) + } + + if !reflect.DeepEqual(reply, exp) { + t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(exp), utils.ToJSON(reply)) + } +}