diff --git a/data/conf/samples/routes_cases_internal/cgrates.json b/data/conf/samples/routes_cases_internal/cgrates.json new file mode 100644 index 000000000..ebe969bd2 --- /dev/null +++ b/data/conf/samples/routes_cases_internal/cgrates.json @@ -0,0 +1,116 @@ +{ + // CGRateS Configuration file + // this config is used for general_tests/routes_cases_it_test.go + + + "general": { + "log_level": 7, + "reply_timeout": "50s" + }, + + + "data_db": { + "db_type": "*internal" + }, + + + "stor_db": { + "db_type": "*internal" + }, + + + "attributes": { + "enabled": true, + "stats_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "accounts_conns": ["*localhost"] + }, + + + "chargers": { + "enabled": true, + "attributes_conns": ["*internal"] + }, + + "cdrs": { + "enabled": true, + }, + + "resources": { + "enabled": true, + "store_interval": "-1", + }, + + "loaders": [ + { + "id": "*default", + "enabled": true, + "tenant": "cgrates.org", + "tp_in_dir": "/usr/share/cgrates/tariffplans/tutroutes", + "tp_out_dir": "", + "lockfile_path": "", + }, + ], + + "stats": { + "enabled": true, + "store_interval": "-1", + "thresholds_conns": ["*internal"] + }, + + "thresholds": { + "enabled": true, + "store_interval": "-1", + }, + + + "routes": { + "enabled": true, + "prefix_indexed_fields":["*req.Destination"], + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + "rates_conns": ["*internal"] + }, + + + "sessions": { + "enabled": true, + "routes_conns": ["*internal"], + "resources_conns": ["*internal"], + "attributes_conns": ["*internal"], + "rals_conns": ["*internal"], + "cdrs_conns": ["*internal"], + "chargers_conns": ["*internal"] + }, + + + "admins": { + "enabled": true, + }, + + + "rates": { + "enabled": true + }, + + + "actions": { + "enabled": true, + "accounts_conns": ["*localhost"] + }, + + + "accounts": { + "enabled": true + }, + + + "filters": { + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + }, + + } + \ No newline at end of file diff --git a/data/conf/samples/routes_cases_mongo/cgrates.json b/data/conf/samples/routes_cases_mongo/cgrates.json new file mode 100644 index 000000000..6f51fb08c --- /dev/null +++ b/data/conf/samples/routes_cases_mongo/cgrates.json @@ -0,0 +1,120 @@ +{ + // CGRateS Configuration file + // this config is used for general_tests/routes_cases_it_test.go + + + "general": { + "log_level": 7, + "reply_timeout": "50s" + }, + + + "data_db": { + "db_type": "mongo", + "db_name": "10", + "db_port": 27017, + }, + + + "stor_db": { + "db_type": "mongo", + "db_name": "cgrates", + "db_port": 27017, + }, + + + "attributes": { + "enabled": true, + "stats_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "accounts_conns": ["*localhost"] + }, + + + "chargers": { + "enabled": true, + "attributes_conns": ["*internal"] + }, + + "cdrs": { + "enabled": true, + }, + + "resources": { + "enabled": true, + "store_interval": "-1", + }, + + "loaders": [ + { + "id": "*default", + "enabled": true, + "tenant": "cgrates.org", + "tp_in_dir": "/usr/share/cgrates/tariffplans/tutroutes", + "tp_out_dir": "", + "lockfile_path": "", + }, + ], + + "stats": { + "enabled": true, + "store_interval": "-1", + "thresholds_conns": ["*internal"] + }, + + "thresholds": { + "enabled": true, + "store_interval": "-1", + }, + + + "routes": { + "enabled": true, + "prefix_indexed_fields":["*req.Destination"], + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + "rates_conns": ["*internal"] + }, + + + "sessions": { + "enabled": true, + "routes_conns": ["*internal"], + "resources_conns": ["*internal"], + "attributes_conns": ["*internal"], + "rals_conns": ["*internal"], + "cdrs_conns": ["*internal"], + "chargers_conns": ["*internal"] + }, + + + "admins": { + "enabled": true, + }, + + + "rates": { + "enabled": true + }, + + + "actions": { + "enabled": true, + "accounts_conns": ["*localhost"] + }, + + + "accounts": { + "enabled": true + }, + + + "filters": { + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + }, + + } + \ No newline at end of file diff --git a/data/conf/samples/routes_cases_mysql/cgrates.json b/data/conf/samples/routes_cases_mysql/cgrates.json new file mode 100644 index 000000000..06e677d39 --- /dev/null +++ b/data/conf/samples/routes_cases_mysql/cgrates.json @@ -0,0 +1,115 @@ +{ + // CGRateS Configuration file + // this config is used for general_tests/routes_cases_it_test.go + + + "general": { + "log_level": 7, + "reply_timeout": "50s" + }, + + "data_db": { // database used to store runtime data (eg: accounts, cdr stats) + "db_type": "redis", // data_db type: + "db_port": 6379, // data_db port to reach the database + "db_name": "10", // data_db database name to connect to + }, + + "stor_db": { + "db_password": "CGRateS.org", + }, + + "attributes": { + "enabled": true, + "stats_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "accounts_conns": ["*localhost"] + }, + + + "chargers": { + "enabled": true, + "attributes_conns": ["*internal"] + }, + + "cdrs": { + "enabled": true, + }, + + "resources": { + "enabled": true, + "store_interval": "-1", + }, + + "loaders": [ + { + "id": "*default", + "enabled": true, + "tenant": "cgrates.org", + "tp_in_dir": "/usr/share/cgrates/tariffplans/tutroutes", + "tp_out_dir": "", + "lockfile_path": "", + }, + ], + + "stats": { + "enabled": true, + "store_interval": "-1", + "thresholds_conns": ["*internal"] + }, + + "thresholds": { + "enabled": true, + "store_interval": "-1", + }, + + + "routes": { + "enabled": true, + "prefix_indexed_fields":["*req.Destination"], + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + "rates_conns": ["*internal"] + }, + + + "sessions": { + "enabled": true, + "routes_conns": ["*internal"], + "resources_conns": ["*internal"], + "attributes_conns": ["*internal"], + "rals_conns": ["*internal"], + "cdrs_conns": ["*internal"], + "chargers_conns": ["*internal"] + }, + + + "admins": { + "enabled": true, + }, + + + "rates": { + "enabled": true + }, + + + "actions": { + "enabled": true, + "accounts_conns": ["*localhost"] + }, + + + "accounts": { + "enabled": true + }, + + + "filters": { + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "accounts_conns": ["*internal"], + }, + + } + \ No newline at end of file diff --git a/data/tariffplans/tutroutes/Accounts.csv b/data/tariffplans/tutroutes/Accounts.csv new file mode 100644 index 000000000..1aa22f508 --- /dev/null +++ b/data/tariffplans/tutroutes/Accounts.csv @@ -0,0 +1,3 @@ +#Tenant,ID,FilterIDs,Weights,Opts,BalanceID,BalanceFilterIDs,BalanceWeights,BalanceType,BalanceUnits,BalanceUnitFactors,BalanceOpts,BalanceCostIncrements,BalanceAttributeIDs,BalanceRateProfileIDs,ThresholdIDs + +cgrates.org,1001,*string:~*req.Account:1001,,,Concrete1,,;30,*concrete,15,,,;1s;0;0.01;,,,*none \ No newline at end of file diff --git a/data/tariffplans/tutroutes/Routes.csv b/data/tariffplans/tutroutes/Routes.csv index 6479a98bf..45a5a7c96 100644 --- a/data/tariffplans/tutroutes/Routes.csv +++ b/data/tariffplans/tutroutes/Routes.csv @@ -1,7 +1,7 @@ #Tenant,ID,FilterIDs,Weights,Sorting,SortingParameters,RouteID,RouteFilterIDs,RouteAccountIDs,RouteRateProfileIDs,RouteResourceIDs,RouteStatIDs,RouteWeights,RouteBlocker,RouteParameters cgrates.org,ROUTE_ACNT_1001,*string:~*req.Account:1001,,*weight,,vendor1,FLTR_DEST_1003,,,,,;10,,, -cgrates.org,ROUTE_ACNT_1001,,,,,vendor2,*gte:~*accounts.1001.BalanceMap.*monetary[0].Value:10,,,,,;20,,, +cgrates.org,ROUTE_ACNT_1001,,,,,vendor2,*gte:~*accounts.1001.Balance[Concrete1].Units:10,,,,,;20,,, cgrates.org,ROUTE_ACNT_1001,,,,,vendor3,FLTR_DEST_1003;*prefix:~*req.Account:10,,,,,;40,,, cgrates.org,ROUTE_ACNT_1001,,,,,vendor4,,,,,,;35,,, diff --git a/general_tests/routes_cases_it_test.go b/general_tests/routes_cases_it_test.go new file mode 100644 index 000000000..efde65479 --- /dev/null +++ b/general_tests/routes_cases_it_test.go @@ -0,0 +1,1689 @@ +//go:build integration +// +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 ( + "path" + "reflect" + "sort" + "testing" + + "github.com/cgrates/birpc" + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/loaders" + "github.com/cgrates/cgrates/utils" +) + +var ( + rtsCaseSv1CfgPath string + rtsCaseSv1Cfg *config.CGRConfig + rtsCaseSv1BiRpc *birpc.Client + rtsCaseSv1ConfDIR string //run tests for specific configuration + + sTestsRtsCaseSV1 = []func(t *testing.T){ + testV1RtsCaseLoadConfig, + testV1RtsCaseInitDataDb, + testV1RtsCaseResetStorDb, + testV1RtsCaseStartEngine, + testV1RtsCaseRpcConn, + testV1RtsCaseFromFolder, + testV1RtsCaseGetRoutesAfterLoading, + testV1RtsCasesSortingRoutesWeightAccountValue, + /* + testV1RtsCasesSortingRoutesWeightAllRoutes, + testV1RtsCasesSortingRoutesWeightNotMatchingValue, + testV1RtsCasesSortingRoutesLowestCost, + testV1RtsCasesSortingRoutesLowestCostDefaultUsage, + testV1RtsCasesSortingRoutesLCSetStatsAndResForMatching, + testV1RtsCasesSortingRoutesLowestCostStats, + testV1RtsCasesSortingRoutesLowestCosMatchingAllRoutes, + testV1RtsCasesSortingRoutesLowestCosMaxCost, + testV1RtsCasesSortingRoutesLowestCosMaxCostNotMatch, + testV1RtsCasesSortingRoutesProcessMetrics, + testV1RtsCasesSortingRoutesQOS, + testV1RtsCasesSortingRoutesQOSAllRoutes, + testV1RtsCasesSortingRoutesQOSNotFound, + testV1RtsCasesSortingRoutesAllocateResources, + testV1RtsCasesSortingRoutesReasNotAllRoutes, + testV1RtsCasesSortingRoutesReasAllRoutes, + testV1RtsCasesRoutesProcessStatsForLoadRtsSorting, + testV1RtsCasesRoutesLoadRtsSorting, + testV1RtsCasesSortRoutesHigherCostV2V3, + testV1RtsCasesSortRoutesHigherCostAllocateRes, + testV1RtsCasesSortRoutesHigherCostV1V3, + testV1RtsCasesSortRoutesHigherCostAllRoutes, + */ + testV1RtsCaseStopEngine, + } +) + +// Test start here +func TestRoutesCaseV1IT(t *testing.T) { + switch *dbType { + case utils.MetaInternal: + rtsCaseSv1ConfDIR = "routes_cases_internal" + case utils.MetaMySQL: + rtsCaseSv1ConfDIR = "routes_cases_mysql" + case utils.MetaMongo: + rtsCaseSv1ConfDIR = "routes_cases_mongo" + case utils.MetaPostgres: + t.SkipNow() + default: + t.Fatal("Unknown Database type") + } + for _, stest := range sTestsRtsCaseSV1 { + t.Run(rtsCaseSv1ConfDIR, stest) + } +} + +func testV1RtsCaseLoadConfig(t *testing.T) { + var err error + rtsCaseSv1CfgPath = path.Join(*dataDir, "conf", "samples", rtsCaseSv1ConfDIR) + if rtsCaseSv1Cfg, err = config.NewCGRConfigFromPath(context.Background(), rtsCaseSv1CfgPath); err != nil { + t.Error(err) + } +} + +func testV1RtsCaseInitDataDb(t *testing.T) { + if err := engine.InitDataDB(rtsCaseSv1Cfg); err != nil { + t.Fatal(err) + } +} + +// Wipe out the cdr database +func testV1RtsCaseResetStorDb(t *testing.T) { + if err := engine.InitStorDB(rtsCaseSv1Cfg); err != nil { + t.Fatal(err) + } +} + +func testV1RtsCaseStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(rtsCaseSv1CfgPath, *waitRater); err != nil { + t.Fatal(err) + } +} + +func testV1RtsCaseRpcConn(t *testing.T) { + var err error + rtsCaseSv1BiRpc, err = newBiRPCClient(rtsCaseSv1Cfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } +} + +func testV1RtsCaseFromFolder(t *testing.T) { + caching := utils.MetaReload + if rtsCaseSv1Cfg.DataDbCfg().Type == utils.Internal { + caching = utils.MetaNone + } + var reply string + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.LoaderSv1Load, + &loaders.ArgsProcessFolder{ + // StopOnError: true, + Caching: utils.StringPointer(caching), + }, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned:", reply) + } +} + +func testV1RtsCaseGetRoutesAfterLoading(t *testing.T) { + // ROUTE_ACNT_1001 + expRt1 := &engine.APIRouteProfile{ + ID: "ROUTE_ACNT_1001", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Sorting: "*weight", + SortingParameters: []string{}, + Routes: []*engine.ExternalRoute{ + { + ID: "vendor1", + FilterIDs: []string{"FLTR_DEST_1003"}, + Weights: ";10", + }, + { + ID: "vendor2", + FilterIDs: []string{"*gte:~*accounts.1001.Balance[Concrete1].Units:10"}, + Weights: ";20", + }, + { + ID: "vendor3", + FilterIDs: []string{"FLTR_DEST_1003", "*prefix:~*req.Account:10"}, + Weights: ";40", + }, + { + ID: "vendor4", + Weights: ";35", + }, + }, + } + var reply *engine.APIRouteProfile + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ID: "ROUTE_ACNT_1001", Tenant: "cgrates.org"}}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + if !reflect.DeepEqual(expRt1, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt1), utils.ToJSON(reply)) + } + } + + // ROUTE_ACNT_1002 + expRt2 := &engine.APIRouteProfile{ + ID: "ROUTE_ACNT_1002", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1002"}, + Sorting: "*lc", + SortingParameters: []string{}, + Routes: []*engine.ExternalRoute{ + { + ID: "vendor1", + FilterIDs: []string{"*lte:~*resources.RES_GRP1.TotalUsage:5"}, + RateProfileIDs: []string{"RP_VENDOR1"}, + Weights: ";0", + }, + { + ID: "vendor2", + FilterIDs: []string{"*gte:~*stats.STATS_VENDOR_2.*acd:1m"}, + RateProfileIDs: []string{"RP_VENDOR2"}, + Weights: ";0", + }, + { + ID: "vendor3", + RateProfileIDs: []string{"RP_VENDOR2"}, + Weights: ";10", + }, + { + ID: "vendor4", + FilterIDs: []string{"*ai:~*req.AnswerTime:2013-06-01T00:00:00Z|2013-06-01T10:00:00Z"}, + RateProfileIDs: []string{"RP_STANDARD"}, + Weights: ";30", + }, + }, + } + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantID{ID: "ROUTE_ACNT_1002", Tenant: "cgrates.org"}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + if !reflect.DeepEqual(expRt2, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt2), utils.ToJSON(reply)) + } + } + + // ROUTE_ACNT_1003 + expRt3 := &engine.APIRouteProfile{ + ID: "ROUTE_ACNT_1003", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1003"}, + Sorting: "*qos", + SortingParameters: []string{"*acd", "*tcc"}, + Routes: []*engine.ExternalRoute{ + { + ID: "vendor1", + StatIDs: []string{"STATS_VENDOR_1"}, + Weights: ";0", + }, + { + ID: "vendor2", + FilterIDs: []string{"*prefix:~*req.Destination:10"}, + StatIDs: []string{"STATS_VENDOR_2"}, + Weights: ";0", + }, + { + ID: "vendor3", + FilterIDs: []string{"*gte:~*stats.STATS_VENDOR_1.*tcc:6"}, + StatIDs: []string{"STATS_VENDOR_1"}, + Weights: ";20", + }, + }, + } + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantID{ID: "ROUTE_ACNT_1003", Tenant: "cgrates.org"}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + sort.Strings(reply.SortingParameters) + sort.Strings(expRt1.SortingParameters) + if !reflect.DeepEqual(expRt3, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt3), utils.ToJSON(reply)) + } + } + + // ROUTE_ACNT_1004 + expRt4 := &engine.APIRouteProfile{ + ID: "ROUTE_ACNT_1004", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1004"}, + Sorting: "*reas", + SortingParameters: []string{}, + Routes: []*engine.ExternalRoute{ + { + ID: "vendor1", + ResourceIDs: []string{"RES_GRP1"}, + Weights: ";0", + }, + { + ID: "vendor2", + ResourceIDs: []string{"RES_GRP2"}, + Weights: ";0", + }, + { + ID: "vendor3", + FilterIDs: []string{"*gte:~*resources.RES_GRP1.TotalUsage:9"}, + ResourceIDs: []string{"RES_GRP2"}, + Weights: ";10", + }, + }, + } + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantID{ID: "ROUTE_ACNT_1004", Tenant: "cgrates.org"}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + if !reflect.DeepEqual(expRt4, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt4), utils.ToJSON(reply)) + } + } + + // ROUTE_ACNT_1005 + expRt5 := &engine.APIRouteProfile{ + ID: "ROUTE_ACNT_1005", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1005"}, + Sorting: "*load", + SortingParameters: []string{"vendor1:3", "*default:2"}, + Routes: []*engine.ExternalRoute{ + { + ID: "vendor1", + StatIDs: []string{"STATS_VENDOR_1:*sum#1"}, + }, + { + ID: "vendor2", + StatIDs: []string{"STATS_VENDOR_2:*sum#1"}, + Weights: ";10", + }, + { + ID: "vendor3", + StatIDs: []string{"STATS_VENDOR_2:*distinct#~*req.Usage"}, + }, + }, + } + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantID{ID: "ROUTE_ACNT_1005", Tenant: "cgrates.org"}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + sort.Strings(reply.SortingParameters) + sort.Strings(expRt5.SortingParameters) + if !reflect.DeepEqual(expRt5, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt5), utils.ToJSON(reply)) + } + } + + // ROUTE_STATS1 + expRt6 := &engine.APIRouteProfile{ + ID: "ROUTE_HC1", + Tenant: "cgrates.org", + FilterIDs: []string{"Fltr_tcc"}, + Sorting: "*hc", + SortingParameters: []string{}, + Routes: []*engine.ExternalRoute{ + { + ID: "route1", + FilterIDs: []string{"*gte:~*resources.RES_GRP2.Available:6"}, + RateProfileIDs: []string{"RP_VENDOR2"}, + ResourceIDs: []string{"RES_GRP2"}, + Weights: ";20", + }, + { + ID: "route2", + FilterIDs: []string{"*gte:~*resources.RES_GRP1.TotalUsage:9"}, + RateProfileIDs: []string{"RP_VENDOR1"}, + ResourceIDs: []string{"RES_GRP1"}, + Weights: ";20", + }, + { + ID: "route3", + RateProfileIDs: []string{"RP_VENDOR1"}, + ResourceIDs: []string{"RES_GRP2"}, + Weights: ";10", + }, + }, + } + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.AdminSv1GetRouteProfile, + &utils.TenantID{ID: "ROUTE_HC1", Tenant: "cgrates.org"}, + &reply); err != nil { + t.Error(err) + } else { + sort.Slice(reply.Routes, func(i, j int) bool { + return reply.Routes[i].ID < reply.Routes[j].ID + }) + if !reflect.DeepEqual(expRt6, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt6), utils.ToJSON(reply)) + } + } +} + +func testV1RtsCasesSortingRoutesWeightAccountValue(t *testing.T) { + ev := &utils.CGREvent{ + ID: "WEIGHT_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1001", + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1001", + Sorting: "*weight", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Weight: 35., + }, + }, + /* + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Weight: 20., + }, + }, + */ + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1BiRpc.Call(context.Background(), utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +/* +func testV1RtsCasesSortingRoutesWeightAllRoutes(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "WEIGHT_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "1003", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1001", + Sorting: "*weight", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Weight: 40., + }, + }, + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Weight: 35., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Weight: 20., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Weight: 10., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesWeightNotMatchingValue(t *testing.T) { + //change account 1001 balance for not matching vendor2 + attrBal := &utils.AttrSetBalance{ + Tenant: "cgrates.org", + Account: "1001", + BalanceType: utils.MetaMonetary, + Value: 5, + Balance: map[string]interface{}{ + utils.ID: utils.MetaDefault, + }, + } + var result string + if err := rtsCaseSv1Rpc.Call(utils.APIerSv1SetBalance, attrBal, + &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Errorf("Unexpected result returned") + } + + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "WEIGHT_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1001", + utils.Destination: "1003", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1001", + Sorting: "*weight", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Weight: 40., + }, + }, + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Weight: 35., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Weight: 10., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLowestCost(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.Usage: "2m30s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1002", + Sorting: "*lc", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 10., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Cost: 0.2505, + utils.RatingPlanID: "RP_VENDOR1", + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + //gonna match one route because the totalUsage by ne-allocated resources is 0 + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLowestCostDefaultUsage(t *testing.T) { + // default usage given by routes is 1m + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1002", + Sorting: "*lc", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Cost: 0.0498, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 10., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Cost: 0.1002, + utils.RatingPlanID: "RP_VENDOR1", + utils.Weight: 0., + }, + }, + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Cost: 0.6, + utils.RatingPlanID: "RP_STANDARD", + utils.Weight: 30., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + //gonna match one route because the totalUsage by ne-allocated resources is 0 + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLCSetStatsAndResForMatching(t *testing.T) { + //not gonna match our vendor1 filter because 6 > 5 + ev := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 6, + } + var reply string + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + ev, &reply); err != nil { + t.Error(err) + } else if reply != "RES_GRP1" { + t.Errorf("Unexpected reply returned: %s", reply) + } + + //gonna match one stats for matching vendor 2 acd filter + var result []string + expected := []string{"STATS_VENDOR_2", "STATS_TCC1"} + ev1 := &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Category: "vendor2", + utils.Usage: "2m30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.0, + }, + }, + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } else { + sort.Strings(result) + sort.Strings(expected) + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, result) + } + } +} + +func testV1RtsCasesSortingRoutesLowestCostStats(t *testing.T) { + //not gonna match vendor1 because of its TotalUsage by allocating resources + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "2m30s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1002", + Sorting: "*lc", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 10., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 0., + }, + }, + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Cost: 1.5, + utils.RatingPlanID: "RP_STANDARD", + utils.Weight: 30., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + //gonna match one route because the totalUsage by ne-allocated resources is 0 + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLowestCosMatchingAllRoutes(t *testing.T) { + // deallocate resources for matching vendor1 + evRes := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 4, + } + var result string + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + evRes, &result); err != nil { + t.Error(err) + } else if result != "RES_GRP1" { + t.Errorf("Unexpected result returned: %s", result) + } + + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "2m30s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1002", + Sorting: "*lc", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 10., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 0., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Cost: 0.2505, + utils.RatingPlanID: "RP_VENDOR1", + utils.Weight: 0., + }, + }, + { + RouteID: "vendor4", + SortingData: map[string]interface{}{ + utils.Cost: 1.5, + utils.RatingPlanID: "RP_STANDARD", + utils.Weight: 30., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLowestCosMaxCost(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + MaxCost: "0.35", + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "2m30s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1002", + Sorting: "*lc", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 10., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Cost: 0.1245, + utils.RatingPlanID: "RP_VENDOR2", + utils.Weight: 0., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Cost: 0.2505, + utils.RatingPlanID: "RP_VENDOR1", + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expSrtdRoutes, reply) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesLowestCosMaxCostNotMatch(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + MaxCost: "0.05", + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1002", + utils.Destination: "1003", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "2m30s", + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) + } +} + +func testV1RtsCasesSortingRoutesProcessMetrics(t *testing.T) { + //we will process this stats 2 times + //Vendor2 + expected := []string{"STATS_TCC1", "STATS_VENDOR_2"} + ev1 := &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Category: "vendor2", + utils.Usage: "2m30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.0, + }, + }, + } + var result []string + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(result) + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, result) + } + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(result) + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, result) + } + } + + //Vendor1 + expected = []string{"STATS_TCC1", "STATS_VENDOR_1"} + ev1 = &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Category: "vendor1", + utils.Usage: "2m30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.0, + }, + }, + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(result) + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, result) + } + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(result) + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, result) + } + } +} + +func testV1RtsCasesSortingRoutesQOS(t *testing.T) { + //not gonna match vendor3 because *tcc is not bigger that 6 + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1003", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "50s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1003", + Sorting: "*qos", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.MetaACC: 1., + utils.MetaACD: 150. * 1e9, + "*sum#1": 3., + "*distinct#~*req.Usage": 1., + utils.MetaTCC: 3., + utils.MetaTCD: 450. * 1e9, + utils.Weight: 0., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.MetaACC: 1., + utils.MetaACD: 150. * 1e9, + "*sum#1": 2., + utils.MetaTCC: 2., + utils.MetaTCD: 300. * 1e9, + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesQOSAllRoutes(t *testing.T) { + // process *tcc metric for matching vendor3 + ev1 := &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Category: "vendor1", + utils.Usage: "2m30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 10.0, + }, + }, + } + var result []string + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &result); err != nil { + t.Error(err) + } + + // match all 3 routes + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1003", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "50s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1003", + Sorting: "*qos", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.MetaACC: 4., + utils.MetaACD: 150. * 1e9, + "*sum#1": 3., + utils.MetaTCC: 12., + utils.MetaTCD: 450. * 1e9, + utils.Weight: 20., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.MetaACC: 4., + utils.MetaACD: 150. * 1e9, + "*sum#1": 3., + utils.MetaTCC: 12., + utils.MetaTCD: 450. * 1e9, + utils.Weight: 0., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.MetaACC: 1., + utils.MetaACD: 150. * 1e9, + "*sum#1": 3., + "*distinct#~*req.Usage": 1., + utils.MetaTCC: 3., + utils.MetaTCD: 450. * 1e9, + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesQOSNotFound(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1008", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Usage: "50s", + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) + } +} + +func testV1RtsCasesSortingRoutesAllocateResources(t *testing.T) { + ev := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 6, + } + var reply string + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + ev, &reply); err != nil { + t.Error(err) + } else if reply != "RES_GRP1" { + t.Errorf("Unexpected reply returned: %s", reply) + } + + ev = &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1004"}, + }, + Units: 7, + } + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + ev, &reply); err != nil { + t.Error(err) + } else if reply != "RES_GRP2" { + t.Errorf("Unexpected reply returned: %s", reply) + } +} + +func testV1RtsCasesSortingRoutesReasNotAllRoutes(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Destination: "1007", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1004", + Sorting: "*reas", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.ResourceUsage: 6.0, + utils.Weight: 0., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.ResourceUsage: 7.0, + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortingRoutesReasAllRoutes(t *testing.T) { + evRs := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 9, + } + var replyStr string + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + evRs, &replyStr); err != nil { + t.Error(err) + } else if replyStr != "RES_GRP1" { + t.Errorf("Unexpected reply returned: %s", replyStr) + } + //allocate more resources for matching + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1004", + utils.Destination: "1007", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1004", + Sorting: "*reas", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.ResourceUsage: 7.0, + utils.Weight: 10., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.ResourceUsage: 7.0, + utils.Weight: 0., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.ResourceUsage: 9.0, + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesRoutesProcessStatsForLoadRtsSorting(t *testing.T) { + // "STATS_VENDOR_1" + var reply []string + expected := []string{"STATS_VENDOR_1", "STATS_TCC1"} + ev1 := &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + //utils.AccountField: "1004", + utils.Category: "vendor1", + utils.Usage: "1m20s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.8, + }, + }, + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &reply); err != nil { + t.Error(err) + } else if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &reply); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(reply) + if !reflect.DeepEqual(reply, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, reply) + } + } + // different usage for *distinct metric + ev1 = &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + //utils.AccountField: "1004", + utils.Category: "vendor1", + utils.Usage: "20s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.8, + }, + }, + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &reply); err != nil { + t.Error(err) + } else if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &reply); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(reply) + if !reflect.DeepEqual(reply, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, reply) + } + } + + // "STATS_VENDOR_2" + expected = []string{"STATS_VENDOR_2", "STATS_TCC1"} + ev1 = &engine.StatsArgsProcessEvent{ + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]interface{}{ + //utils.AccountField: "1004", + utils.Category: "vendor2", + utils.Usage: "30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 0.77, + }, + }, + } + if err := rtsCaseSv1Rpc.Call(utils.StatSv1ProcessEvent, ev1, &reply); err != nil { + t.Error(err) + } else { + sort.Strings(expected) + sort.Strings(reply) + if !reflect.DeepEqual(reply, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, reply) + } + } +} + +func testV1RtsCasesRoutesLoadRtsSorting(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1005", + //utils.Destination: "1007", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_ACNT_1005", + Sorting: "*load", + Routes: []*engine.SortedRoute{ + { + RouteID: "vendor3", + SortingData: map[string]interface{}{ + utils.Load: 2., + utils.Ratio: 2., + utils.Weight: 0., + }, + }, + { + RouteID: "vendor2", + SortingData: map[string]interface{}{ + utils.Load: 4., + utils.Ratio: 2., + utils.Weight: 10., + }, + }, + { + RouteID: "vendor1", + SortingData: map[string]interface{}{ + utils.Load: 7., + utils.Ratio: 3., + utils.Weight: 0., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortRoutesHigherCostV2V3(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1008", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.Usage: "3m25s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_HC1", + Sorting: "*hc", + Routes: []*engine.SortedRoute{ + { + RouteID: "route2", + SortingData: map[string]interface{}{ + utils.Cost: 0.34235, + utils.RatingPlanID: "RP_VENDOR1", + utils.ResourceUsage: 9., + utils.Weight: 20., + }, + }, + { + RouteID: "route3", + SortingData: map[string]interface{}{ + utils.Cost: 0.34235, + utils.RatingPlanID: "RP_VENDOR1", + utils.ResourceUsage: 7., + utils.Weight: 10., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortRoutesHigherCostAllocateRes(t *testing.T) { + // to match route 1, RES_GRP2 must have *gte available 6 resources + // first we have to remove them + var result string + evRs := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1004"}, + }, + Units: 7, + } + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1ReleaseResources, + evRs, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Errorf("Unexpected result returned: %s", result) + } + + evRs = &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 7, + } + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1ReleaseResources, + evRs, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Errorf("Unexpected result returned: %s", result) + } + + evRs = &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1004"}, + }, + Units: 1, + } + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + evRs, &result); err != nil { + t.Error(err) + } else if result != "RES_GRP2" { + t.Errorf("Unexpected result returned: %s", result) + } + + // also, to not match route2, totalUsage of RES_GRP1 must be lower than 9 + evRs = &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 4, + } + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + evRs, &result); err != nil { + t.Error(err) + } else if result != "RES_GRP1" { + t.Errorf("Unexpected result returned: %s", result) + } +} + +func testV1RtsCasesSortRoutesHigherCostV1V3(t *testing.T) { + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1008", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.Usage: "3m25s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_HC1", + Sorting: "*hc", + Routes: []*engine.SortedRoute{ + { + RouteID: "route3", + SortingData: map[string]interface{}{ + utils.Cost: 0.34235, + utils.RatingPlanID: "RP_VENDOR1", + utils.ResourceUsage: 1., + utils.Weight: 10., + }, + }, + { + RouteID: "route1", + SortingData: map[string]interface{}{ + utils.Cost: 0.17015, + utils.RatingPlanID: "RP_VENDOR2", + utils.ResourceUsage: 1., + utils.Weight: 20., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} + +func testV1RtsCasesSortRoutesHigherCostAllRoutes(t *testing.T) { + //allocate for matching all routes + evRs := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1002"}, + }, + Units: 9, + } + var result string + if err := rtsCaseSv1Rpc.Call(utils.ResourceSv1AllocateResources, + evRs, &result); err != nil { + t.Error(err) + } else if result != "RES_GRP1" { + t.Errorf("Unexpected result returned: %s", result) + } + ev := &engine.ArgsGetRoutes{ + CGREvent: &utils.CGREvent{ + ID: "LC_SORT", + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.AccountField: "1008", + utils.Destination: "1007", + utils.SetupTime: "2013-06-01T00:00:00Z", + utils.Usage: "3m25s", + }, + }, + } + expSrtdRoutes := &engine.SortedRoutesList{ + { + ProfileID: "ROUTE_HC1", + Sorting: "*hc", + Routes: []*engine.SortedRoute{ + { + RouteID: "route2", + SortingData: map[string]interface{}{ + utils.Cost: 0.34235, + utils.RatingPlanID: "RP_VENDOR1", + utils.ResourceUsage: 9., + utils.Weight: 20., + }, + }, + { + RouteID: "route3", + SortingData: map[string]interface{}{ + utils.Cost: 0.34235, + utils.RatingPlanID: "RP_VENDOR1", + utils.ResourceUsage: 1., + utils.Weight: 10., + }, + }, + { + RouteID: "route1", + SortingData: map[string]interface{}{ + utils.Cost: 0.17015, + utils.RatingPlanID: "RP_VENDOR2", + utils.ResourceUsage: 1., + utils.Weight: 20., + }, + }, + }, + }, + } + var reply *engine.SortedRoutesList + if err := rtsCaseSv1Rpc.Call(utils.RouteSv1GetRoutes, + ev, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply, expSrtdRoutes) { + t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply)) + } +} +*/ + +func testV1RtsCaseStopEngine(t *testing.T) { + if err := engine.KillEngine(100); err != nil { + t.Error(err) + } +}