// +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 general_tests 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 ( splSv1CfgPath string splSv1Cfg *config.CGRConfig splSv1Rpc *rpc.Client splPrf *engine.SupplierProfile splSv1ConfDIR string //run tests for specific configuration ) var sTestsSupplierSV1 = []func(t *testing.T){ testV1SplSLoadConfig, testV1SplSInitDataDb, testV1SplSResetStorDb, testV1SplSStartEngine, testV1SplSRpcConn, testV1SplSFromFolder, testV1SplSSetSupplierProfilesWithoutRatingPlanIDs, //tests for *reas sorting strategy testV1SplSAddNewSplPrf, testV1SplSAddNewResPrf, testV1SplSPopulateResUsage, testV1SplSGetSortedSuppliers, //tests for *reds sorting strategy testV1SplSAddNewSplPrf2, testV1SplSGetSortedSuppliers2, testV1SplSStopEngine, } // Test start here func TestSuplSV1ITMySQL(t *testing.T) { splSv1ConfDIR = "tutmysql" for _, stest := range sTestsSupplierSV1 { t.Run(splSv1ConfDIR, stest) } } func TestSuplSV1ITMongo(t *testing.T) { splSv1ConfDIR = "tutmongo" for _, stest := range sTestsSupplierSV1 { t.Run(splSv1ConfDIR, stest) } } func testV1SplSLoadConfig(t *testing.T) { var err error splSv1CfgPath = path.Join(*dataDir, "conf", "samples", splSv1ConfDIR) if splSv1Cfg, err = config.NewCGRConfigFromPath(splSv1CfgPath); err != nil { t.Error(err) } } func testV1SplSInitDataDb(t *testing.T) { if err := engine.InitDataDb(splSv1Cfg); err != nil { t.Fatal(err) } } // Wipe out the cdr database func testV1SplSResetStorDb(t *testing.T) { if err := engine.InitStorDb(splSv1Cfg); err != nil { t.Fatal(err) } } func testV1SplSStartEngine(t *testing.T) { if _, err := engine.StopStartEngine(splSv1CfgPath, *waitRater); err != nil { t.Fatal(err) } } func testV1SplSRpcConn(t *testing.T) { var err error splSv1Rpc, err = jsonrpc.Dial("tcp", splSv1Cfg.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed if err != nil { t.Fatal("Could not connect to rater: ", err.Error()) } } func testV1SplSFromFolder(t *testing.T) { var reply string attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testit")} if err := splSv1Rpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil { t.Error(err) } time.Sleep(100 * time.Millisecond) } func testV1SplSSetSupplierProfilesWithoutRatingPlanIDs(t *testing.T) { var reply *engine.SupplierProfile if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE2"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err) } splPrf = &engine.SupplierProfile{ Tenant: "cgrates.org", ID: "TEST_PROFILE2", Sorting: utils.MetaLC, Suppliers: []*engine.Supplier{ { ID: "SPL1", FilterIDs: []string{"FLTR_1"}, AccountIDs: []string{"accc"}, Weight: 20, Blocker: false, }, }, Weight: 10, } var result string if err := splSv1Rpc.Call("ApierV1.SetSupplierProfile", splPrf, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE2"}, &reply); err != nil { t.Error(err) } else if !reflect.DeepEqual(splPrf, reply) { t.Errorf("Expecting: %+v, received: %+v", splPrf, reply) } ev := &engine.ArgsGetSuppliers{ CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testV1SplSGetLeastCostSuppliers", Event: map[string]interface{}{ utils.Account: "accc", utils.Subject: "1003", utils.Destination: "1002", utils.SetupTime: time.Date(2017, 12, 1, 14, 25, 0, 0, time.UTC), utils.Usage: "1m20s", }, }, } var suplsReply engine.SortedSuppliers if err := splSv1Rpc.Call(utils.SupplierSv1GetSuppliers, ev, &suplsReply); err.Error() != utils.NewErrServerError(utils.NewErrMandatoryIeMissing("RatingPlanIDs")).Error() { t.Errorf("Expected error MANDATORY_IE_MISSING: [RatingPlanIDs] recieved:%v\n", err) } if err := splSv1Rpc.Call("ApierV1.RemoveSupplierProfile", utils.TenantID{ Tenant: splPrf.Tenant, ID: splPrf.ID, }, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } } func testV1SplSAddNewSplPrf(t *testing.T) { var reply *engine.SupplierProfile if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "SPL_ResourceTest"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err) } //create a new Supplier Profile to test *reas and *reds sorting strategy splPrf = &engine.SupplierProfile{ Tenant: "cgrates.org", ID: "SPL_ResourceTest", Sorting: utils.MetaReas, FilterIDs: []string{"*string:~CustomField:ResourceTest"}, Suppliers: []*engine.Supplier{ //supplier1 will have ResourceUsage = 11 { ID: "supplier1", ResourceIDs: []string{"ResourceSupplier1", "Resource2Supplier1"}, Weight: 20, Blocker: false, }, //supplier2 and supplier3 will have the same ResourceUsage = 7 { ID: "supplier2", ResourceIDs: []string{"ResourceSupplier2"}, Weight: 20, Blocker: false, }, { ID: "supplier3", ResourceIDs: []string{"ResourceSupplier3"}, Weight: 35, Blocker: false, }, }, Weight: 10, } var result string if err := splSv1Rpc.Call("ApierV1.SetSupplierProfile", splPrf, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "SPL_ResourceTest"}, &reply); err != nil { t.Error(err) } else if !reflect.DeepEqual(splPrf, reply) { t.Errorf("Expecting: %+v, received: %+v", splPrf, reply) } } func testV1SplSAddNewResPrf(t *testing.T) { var result string //add ResourceSupplier1 rPrf := &engine.ResourceProfile{ Tenant: "cgrates.org", ID: "ResourceSupplier1", FilterIDs: []string{"*string:~Supplier:supplier1", "*string:~ResID:ResourceSupplier1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), }, UsageTTL: time.Duration(1) * time.Minute, Limit: 10, Stored: true, Weight: 20, ThresholdIDs: []string{utils.META_NONE}, } if err := splSv1Rpc.Call("ApierV1.SetResourceProfile", rPrf, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } //add Resource2Supplier1 rPrf2 := &engine.ResourceProfile{ Tenant: "cgrates.org", ID: "Resource2Supplier1", FilterIDs: []string{"*string:~Supplier:supplier1", "*string:~ResID:Resource2Supplier1"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), }, UsageTTL: time.Duration(1) * time.Minute, Limit: 10, Stored: true, Weight: 30, ThresholdIDs: []string{utils.META_NONE}, } if err := splSv1Rpc.Call("ApierV1.SetResourceProfile", rPrf2, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } //add ResourceSupplier2 rPrf3 := &engine.ResourceProfile{ Tenant: "cgrates.org", ID: "ResourceSupplier2", FilterIDs: []string{"*string:~Supplier:supplier2", "*string:~ResID:ResourceSupplier2"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), }, UsageTTL: time.Duration(1) * time.Minute, Limit: 10, Stored: true, Weight: 20, ThresholdIDs: []string{utils.META_NONE}, } if err := splSv1Rpc.Call("ApierV1.SetResourceProfile", rPrf3, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } //add ResourceSupplier2 rPrf4 := &engine.ResourceProfile{ Tenant: "cgrates.org", ID: "ResourceSupplier3", FilterIDs: []string{"*string:~Supplier:supplier3", "*string:~ResID:ResourceSupplier3"}, ActivationInterval: &utils.ActivationInterval{ ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), }, UsageTTL: time.Duration(1) * time.Minute, Limit: 10, Stored: true, Weight: 20, ThresholdIDs: []string{utils.META_NONE}, } if err := splSv1Rpc.Call("ApierV1.SetResourceProfile", rPrf4, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } } func testV1SplSPopulateResUsage(t *testing.T) { var reply string argsRU := utils.ArgRSv1ResourceUsage{ UsageID: "RandomID", CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "Event1", Event: map[string]interface{}{ "Account": "1002", "Supplier": "supplier1", "ResID": "ResourceSupplier1", }, }, Units: 4, } if err := splSv1Rpc.Call(utils.ResourceSv1AllocateResources, argsRU, &reply); err != nil { t.Error(err) } eAllocationMsg := "ResourceSupplier1" if reply != eAllocationMsg { t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) } argsRU = utils.ArgRSv1ResourceUsage{ UsageID: "RandomID2", CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "Event2", Event: map[string]interface{}{ "Account": "1002", "Supplier": "supplier1", "ResID": "Resource2Supplier1", }, }, Units: 7, } if err := splSv1Rpc.Call(utils.ResourceSv1AllocateResources, argsRU, &reply); err != nil { t.Error(err) } eAllocationMsg = "Resource2Supplier1" if reply != eAllocationMsg { t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) } argsRU = utils.ArgRSv1ResourceUsage{ UsageID: "RandomID3", CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "Event3", Event: map[string]interface{}{ "Account": "1002", "Supplier": "supplier2", "ResID": "ResourceSupplier2", }, }, Units: 7, } if err := splSv1Rpc.Call(utils.ResourceSv1AllocateResources, argsRU, &reply); err != nil { t.Error(err) } eAllocationMsg = "ResourceSupplier2" if reply != eAllocationMsg { t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) } argsRU = utils.ArgRSv1ResourceUsage{ UsageID: "RandomID4", CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "Event4", Event: map[string]interface{}{ "Account": "1002", "Supplier": "supplier3", "ResID": "ResourceSupplier3", }, }, Units: 7, } if err := splSv1Rpc.Call(utils.ResourceSv1AllocateResources, argsRU, &reply); err != nil { t.Error(err) } eAllocationMsg = "ResourceSupplier3" if reply != eAllocationMsg { t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) } } func testV1SplSGetSortedSuppliers(t *testing.T) { ev := &engine.ArgsGetSuppliers{ CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testV1SplSGetSortedSuppliers", Event: map[string]interface{}{ "CustomField": "ResourceTest", }, }, } expSupplierIDs := []string{"supplier3", "supplier2", "supplier1"} var suplsReply engine.SortedSuppliers if err := splSv1Rpc.Call(utils.SupplierSv1GetSuppliers, ev, &suplsReply); err != nil { t.Error(err) } else { rcvSupl := make([]string, len(suplsReply.SortedSuppliers)) for i, supl := range suplsReply.SortedSuppliers { rcvSupl[i] = supl.SupplierID } if suplsReply.ProfileID != "SPL_ResourceTest" { t.Errorf("Expecting: SPL_ResourceTest, received: %s", suplsReply.ProfileID) } if !reflect.DeepEqual(rcvSupl, expSupplierIDs) { t.Errorf("Expecting: %+v, \n received: %+v", expSupplierIDs, utils.ToJSON(suplsReply)) } } } func testV1SplSAddNewSplPrf2(t *testing.T) { var reply *engine.SupplierProfile if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "SPL_ResourceDescendent"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err) } //create a new Supplier Profile to test *reas and *reds sorting strategy splPrf = &engine.SupplierProfile{ Tenant: "cgrates.org", ID: "SPL_ResourceDescendent", Sorting: utils.MetaReds, FilterIDs: []string{"*string:~CustomField:ResourceDescendent"}, Suppliers: []*engine.Supplier{ //supplier1 will have ResourceUsage = 11 { ID: "supplier1", ResourceIDs: []string{"ResourceSupplier1", "Resource2Supplier1"}, Weight: 20, Blocker: false, }, //supplier2 and supplier3 will have the same ResourceUsage = 7 { ID: "supplier2", ResourceIDs: []string{"ResourceSupplier2"}, Weight: 20, Blocker: false, }, { ID: "supplier3", ResourceIDs: []string{"ResourceSupplier3"}, Weight: 35, Blocker: false, }, }, Weight: 10, } var result string if err := splSv1Rpc.Call("ApierV1.SetSupplierProfile", splPrf, &result); err != nil { t.Error(err) } else if result != utils.OK { t.Error("Unexpected reply returned", result) } if err := splSv1Rpc.Call("ApierV1.GetSupplierProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "SPL_ResourceDescendent"}, &reply); err != nil { t.Error(err) } else if !reflect.DeepEqual(splPrf, reply) { t.Errorf("Expecting: %+v, received: %+v", splPrf, reply) } } func testV1SplSGetSortedSuppliers2(t *testing.T) { ev := &engine.ArgsGetSuppliers{ CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "testV1SplSGetSortedSuppliers2", Event: map[string]interface{}{ "CustomField": "ResourceDescendent", }, }, } expSupplierIDs := []string{"supplier1", "supplier3", "supplier2"} var suplsReply engine.SortedSuppliers if err := splSv1Rpc.Call(utils.SupplierSv1GetSuppliers, ev, &suplsReply); err != nil { t.Error(err) } else { rcvSupl := make([]string, len(suplsReply.SortedSuppliers)) for i, supl := range suplsReply.SortedSuppliers { rcvSupl[i] = supl.SupplierID } if suplsReply.ProfileID != "SPL_ResourceDescendent" { t.Errorf("Expecting: SPL_ResourceDescendent, received: %s", suplsReply.ProfileID) } if !reflect.DeepEqual(rcvSupl, expSupplierIDs) { t.Errorf("Expecting: %+v, \n received: %+v", expSupplierIDs, utils.ToJSON(suplsReply)) } } } func testV1SplSStopEngine(t *testing.T) { if err := engine.KillEngine(100); err != nil { t.Error(err) } }