From 38c087d62644963b954b2e622f11dad334691876 Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 11 Jul 2018 06:16:47 -0400 Subject: [PATCH] Add test in apier/v1 for Charger --- apier/v1/chargers.go | 12 ++ apier/v1/chargers_it_test.go | 274 ++++++++++++++++++++++++ data/conf/samples/tutmongo/cgrates.json | 36 +--- data/conf/samples/tutmysql/cgrates.json | 3 + data/tariffplans/tutorial/Chargers.csv | 3 +- dispatcher/chargers.go | 29 ++- engine/chargers.go | 1 - engine/chargers_test.go | 47 ++++ engine/storage_map_datadb.go | 2 +- engine/storage_redis.go | 2 +- utils/consts.go | 4 +- 11 files changed, 367 insertions(+), 46 deletions(-) create mode 100755 apier/v1/chargers_it_test.go create mode 100755 engine/chargers_test.go diff --git a/apier/v1/chargers.go b/apier/v1/chargers.go index b948f1a95..6cb74da8c 100644 --- a/apier/v1/chargers.go +++ b/apier/v1/chargers.go @@ -86,3 +86,15 @@ func (cSv1 *ChargerSv1) Ping(ign string, reply *string) error { *reply = utils.Pong return nil } + +// GetChargerForEvent returns matching ChargerProfile for Event +func (cSv1 *ChargerSv1) GetChargersForEvent(cgrEv *utils.CGREvent, + reply *engine.ChargerProfiles) error { + return cSv1.cS.V1GetChargersForEvent(cgrEv, reply) +} + +// ProcessEvent +func (cSv1 *ChargerSv1) ProcessEvent(args *utils.CGREvent, + reply *[]*utils.CGREvent) error { + return cSv1.cS.V1ProcessEvent(args, reply) +} diff --git a/apier/v1/chargers_it_test.go b/apier/v1/chargers_it_test.go new file mode 100755 index 000000000..2182a1ab7 --- /dev/null +++ b/apier/v1/chargers_it_test.go @@ -0,0 +1,274 @@ +// +build integration + +/* +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 v1 + +import ( + "net/rpc" + "net/rpc/jsonrpc" + "path" + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +var ( + chargerCfgPath string + chargerCfg *config.CGRConfig + chargerRPC *rpc.Client + chargerProfile *engine.ChargerProfile + chargerDelay int + chargerConfigDIR string //run tests for specific configuration +) + +var chargerEvent = []*utils.CGREvent{ + &utils.CGREvent{ // matching Charger1 + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.Account: "1001", + }, + }, + &utils.CGREvent{ // no matching + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.Account: "1010", + "DistinctMatch": "cgrates", + }, + }, +} + +var sTestsCharger = []func(t *testing.T){ + testChargerSInitCfg, + testChargerSInitDataDb, + testChargerSResetStorDb, + testChargerSStartEngine, + testChargerSRPCConn, + testChargerSLoadFromFolder, + testChargerSGetChargersForEvent, + testChargerSProcessEvent, + testChargerSSetChargerProfile, + testChargerSUpdateChargerProfile, + testChargerSRemChargerProfile, + testChargerSPing, + testChargerSKillEngine, +} + +//Test start here +func TestChargerSITMySql(t *testing.T) { + chargerConfigDIR = "tutmysql" + for _, stest := range sTestsCharger { + t.Run(chargerConfigDIR, stest) + } +} + +func TestChargerSITMongo(t *testing.T) { + chargerConfigDIR = "tutmongo" + for _, stest := range sTestsCharger { + t.Run(chargerConfigDIR, stest) + } +} + +func testChargerSInitCfg(t *testing.T) { + var err error + chargerCfgPath = path.Join(*dataDir, "conf", "samples", chargerConfigDIR) + chargerCfg, err = config.NewCGRConfigFromFolder(chargerCfgPath) + if err != nil { + t.Error(err) + } + chargerCfg.DataFolderPath = *dataDir + config.SetCgrConfig(chargerCfg) + switch chargerConfigDIR { + case "tutmongo": + chargerDelay = 2000 + default: + chargerDelay = 1000 + } +} + +func testChargerSInitDataDb(t *testing.T) { + if err := engine.InitDataDb(chargerCfg); err != nil { + t.Fatal(err) + } +} + +// Wipe out the cdr database +func testChargerSResetStorDb(t *testing.T) { + if err := engine.InitStorDb(chargerCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func testChargerSStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(chargerCfgPath, chargerDelay); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func testChargerSRPCConn(t *testing.T) { + var err error + chargerRPC, err = jsonrpc.Dial("tcp", chargerCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal(err) + } +} + +func testChargerSLoadFromFolder(t *testing.T) { + var reply string + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")} + if err := chargerRPC.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil { + t.Error(err) + } + time.Sleep(500 * time.Millisecond) +} + +func testChargerSGetChargersForEvent(t *testing.T) { + chargerProfiles := &engine.ChargerProfiles{ + &engine.ChargerProfile{ + Tenant: "cgrates.org", + ID: "Charger1", + FilterIDs: []string{"*string:Account:1001"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 29, 15, 0, 0, 0, time.UTC), + }, + RunID: "*rated", + AttributeIDs: []string{"ATTR_1001_SIMPLEAUTH"}, + Weight: 20, + }, + } + var result *engine.ChargerProfiles + if err := chargerRPC.Call(utils.ChargerSv1GetChargersForEvent, chargerEvent[1], &result); err == nil || + err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if err := chargerRPC.Call(utils.ChargerSv1GetChargersForEvent, chargerEvent[0], &result); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(result, chargerProfiles) { + t.Errorf("Expecting : %s, received: %s", chargerProfiles, result) + } +} + +func testChargerSProcessEvent(t *testing.T) { + processedEv := &[]*utils.CGREvent{ + &utils.CGREvent{ // matching Charger1 + Tenant: "cgrates.org", + ID: "event1", + Context: utils.StringPointer(utils.MetaChargers), + Event: map[string]interface{}{ + utils.Account: "1001", + "Password": "CGRateS.org", + "RunID": "*rated", + }, + }, + } + var result *[]*utils.CGREvent + if err := chargerRPC.Call(utils.ChargerSv1ProcessEvent, chargerEvent[1], &result); err == nil || + err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if err := chargerRPC.Call(utils.ChargerSv1ProcessEvent, chargerEvent[0], &result); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(result, processedEv) { + t.Errorf("Expecting : %s, received: %s", utils.ToJSON(processedEv), utils.ToJSON(result)) + } +} + +func testChargerSSetChargerProfile(t *testing.T) { + chargerProfile = &engine.ChargerProfile{ + Tenant: "cgrates.org", + ID: "ApierTest", + FilterIDs: []string{"*string:Account:1001", "*string:Account:1002"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + ExpiryTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + }, + RunID: "*default", + AttributeIDs: []string{"Attr1", "Attr2"}, + Weight: 20, + } + var result string + if err := chargerRPC.Call("ApierV1.SetChargerProfile", chargerProfile, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } + var reply *engine.ChargerProfile + if err := chargerRPC.Call("ApierV1.GetChargerProfile", + &utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(chargerProfile, reply) { + t.Errorf("Expecting : %+v, received: %+v", chargerProfile, reply) + } +} + +func testChargerSUpdateChargerProfile(t *testing.T) { + chargerProfile.RunID = "*rated" + var result string + if err := chargerRPC.Call("ApierV1.SetChargerProfile", chargerProfile, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } + var reply *engine.ChargerProfile + if err := chargerRPC.Call("ApierV1.GetChargerProfile", + &utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(chargerProfile, reply) { + t.Errorf("Expecting : %+v, received: %+v", chargerProfile, reply) + } +} + +func testChargerSRemChargerProfile(t *testing.T) { + var resp string + if err := chargerRPC.Call("ApierV1.RemoveChargerProfile", + &utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &resp); err != nil { + t.Error(err) + } else if resp != utils.OK { + t.Error("Unexpected reply returned", resp) + } + var reply *engine.AttributeProfile + if err := chargerRPC.Call("ApierV1.GetChargerProfile", + &utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, + &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testChargerSPing(t *testing.T) { + var resp string + if err := chargerRPC.Call(utils.ChargerSv1Ping, "", &resp); err != nil { + t.Error(err) + } else if resp != utils.Pong { + t.Error("Unexpected reply returned", resp) + } +} + +func testChargerSKillEngine(t *testing.T) { + if err := engine.KillEngine(chargerDelay); err != nil { + t.Error(err) + } +} diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json index 7cd714f24..2e04f97ff 100644 --- a/data/conf/samples/tutmongo/cgrates.json +++ b/data/conf/samples/tutmongo/cgrates.json @@ -71,18 +71,6 @@ "thresholds_conns": [ {"address": "*internal"} ], - "cdrstats_conns": [ - {"address": "*internal"} - ], - "pubsubs_conns": [ - {"address": "*internal"} - ], - "users_conns": [ - {"address": "*internal"} - ], - "aliases_conns": [ - {"address": "*internal"} - ], }, @@ -93,9 +81,6 @@ "cdrs": { "enabled": true, - "cdrstats_conns": [ - {"address": "*internal"} - ], }, @@ -119,19 +104,11 @@ }, -"cdrstats": { +"chargers": { "enabled": true, -}, - - -"pubsubs": { - "enabled": true, -}, - - -"users": { - "enabled": true, - "indexes": ["Uuid"], + "attributes_conns": [ + {"address": "*internal"} + ], }, @@ -169,11 +146,6 @@ }, -"aliases": { - "enabled": true, -}, - - "sessions": { "enabled": true, }, diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json index 86c108843..0c6b064e9 100644 --- a/data/conf/samples/tutmysql/cgrates.json +++ b/data/conf/samples/tutmysql/cgrates.json @@ -232,6 +232,9 @@ "chargers": { "enabled": true, + "attributes_conns": [ + {"address": "*internal"} + ], }, diff --git a/data/tariffplans/tutorial/Chargers.csv b/data/tariffplans/tutorial/Chargers.csv index d9f4caed0..e68860cdf 100644 --- a/data/tariffplans/tutorial/Chargers.csv +++ b/data/tariffplans/tutorial/Chargers.csv @@ -1 +1,2 @@ -#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight \ No newline at end of file +#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight +cgrates.org,Charger1,*string:Account:1001,2014-07-29T15:00:00Z,*rated,ATTR_1001_SIMPLEAUTH,20 \ No newline at end of file diff --git a/dispatcher/chargers.go b/dispatcher/chargers.go index f362e060a..1da34b357 100755 --- a/dispatcher/chargers.go +++ b/dispatcher/chargers.go @@ -25,20 +25,31 @@ import ( func (dS *DispatcherService) ChargerSv1Ping(ign string, reply *string) error { if dS.chargerS == nil { - return utils.NewErrNotConnected(utils.AttributeS) + return utils.NewErrNotConnected(utils.ChargerS) } return dS.chargerS.Call(utils.ChargerSv1Ping, ign, reply) } -func (dS *DispatcherService) ChargerSv1GetChargersForEvent(args *ArgsAttrProcessEventWithApiKey, - reply *engine.AttributeProfile) (err error) { - if dS.attrS == nil { - return utils.NewErrNotConnected(utils.AttributeS) +func (dS *DispatcherService) ChargerSv1GetChargersForEvent(args *CGREvWithApiKey, + reply *engine.ChargerProfiles) (err error) { + if dS.chargerS == nil { + return utils.NewErrNotConnected(utils.ChargerS) } - if err = dS.authorize(utils.AttributeSv1GetAttributeForEvent, args.AttrArgsProcessEvent.CGREvent.Tenant, - args.APIKey, args.AttrArgsProcessEvent.CGREvent.Time); err != nil { + if err = dS.authorize(utils.AttributeSv1GetAttributeForEvent, args.CGREvent.Tenant, + args.APIKey, args.CGREvent.Time); err != nil { return } - return dS.attrS.Call(utils.AttributeSv1GetAttributeForEvent, args.AttrArgsProcessEvent, reply) - + return dS.chargerS.Call(utils.ChargerSv1GetChargersForEvent, args.CGREvent, reply) +} + +func (dS *DispatcherService) ChargerSv1ProcessEvent(args *CGREvWithApiKey, + reply *[]*utils.CGREvent) (err error) { + if dS.chargerS == nil { + return utils.NewErrNotConnected(utils.ChargerS) + } + if err = dS.authorize(utils.AttributeSv1GetAttributeForEvent, args.CGREvent.Tenant, + args.APIKey, args.CGREvent.Time); err != nil { + return + } + return dS.chargerS.Call(utils.ChargerSv1ProcessEvent, args.CGREvent, reply) } diff --git a/engine/chargers.go b/engine/chargers.go index 53ff7ac79..eb1e73b88 100644 --- a/engine/chargers.go +++ b/engine/chargers.go @@ -141,7 +141,6 @@ func (cS *ChargerService) V1ProcessEvent(args *utils.CGREvent, } *reply = rply return - } // V1GetChargersForEvent exposes the list of ordered matching ChargingProfiles for an event diff --git a/engine/chargers_test.go b/engine/chargers_test.go new file mode 100755 index 000000000..5134a5385 --- /dev/null +++ b/engine/chargers_test.go @@ -0,0 +1,47 @@ +/* +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 + +import ( + // "reflect" + // "testing" + // "time" + + "github.com/cgrates/cgrates/config" + //"github.com/cgrates/cgrates/utils" +) + +var ( + chargerSrv *ChargerService + dmCharger *DataManager +) + +func TestChargerPopulateChargerService(t *testing.T) { + data, _ := NewMapStorage() + dmCharger = NewDataManager(data) + defaultCfg, err := config.NewDefaultCGRConfig() + if err != nil { + t.Errorf("Error: %+v", err) + } + + chargerSrv, err = NewChargerService(dmCharger, + &FilterS{dm: dmAtr, cfg: defaultCfg}, nil, defaultCfg) + if err != nil { + t.Errorf("Error: %+v", err) + } +} diff --git a/engine/storage_map_datadb.go b/engine/storage_map_datadb.go index 14be866d2..d539851a1 100644 --- a/engine/storage_map_datadb.go +++ b/engine/storage_map_datadb.go @@ -222,7 +222,7 @@ func (ms *MapStorage) HasDataDrv(category, subject, tenant string) (bool, error) return exists, nil case utils.ResourcesPrefix, utils.ResourceProfilesPrefix, utils.StatQueuePrefix, utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, - utils.FilterPrefix, utils.SupplierProfilePrefix, utils.AttributeProfilePrefix: + utils.FilterPrefix, utils.SupplierProfilePrefix, utils.AttributeProfilePrefix, utils.ChargerProfilePrefix: _, exists := ms.dict[category+utils.ConcatenatedKey(tenant, subject)] return exists, nil } diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 90bd12709..19e9d111c 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -274,7 +274,7 @@ func (rs *RedisStorage) HasDataDrv(category, subject, tenant string) (bool, erro return i == 1, err case utils.ResourcesPrefix, utils.ResourceProfilesPrefix, utils.StatQueuePrefix, utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, - utils.FilterPrefix, utils.SupplierProfilePrefix, utils.AttributeProfilePrefix: + utils.FilterPrefix, utils.SupplierProfilePrefix, utils.AttributeProfilePrefix, utils.ChargerProfilePrefix: i, err := rs.Cmd("EXISTS", category+utils.ConcatenatedKey(tenant, subject)).Int() return i == 1, err } diff --git a/utils/consts.go b/utils/consts.go index 83d22c441..e402f918a 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -696,7 +696,9 @@ const ( // ChargerS APIs const ( - ChargerSv1Ping = "ChargerSv1.Ping" + ChargerSv1Ping = "ChargerSv1.Ping" + ChargerSv1GetChargersForEvent = "ChargerSv1.GetChargersForEvent" + ChargerSv1ProcessEvent = "ChargerSv1.ProcessEvent" ) // ThresholdS APIs