From 6d7f60e4e208deab0711afa45e66110255b5d819 Mon Sep 17 00:00:00 2001 From: porosnicuadrian Date: Mon, 24 May 2021 17:16:03 +0300 Subject: [PATCH] Finished tests for routes cases in case of sorting --- engine/routes.go | 6 +- general_tests/routes_cases_it_test.go | 336 +++++++++++++++++++++++--- 2 files changed, 309 insertions(+), 33 deletions(-) diff --git a/engine/routes.go b/engine/routes.go index df0d12867..51a8bd595 100644 --- a/engine/routes.go +++ b/engine/routes.go @@ -710,7 +710,7 @@ func (rpS *RouteService) sortedRoutesForEvent(tnt string, args *ArgsGetRoutes) ( } var startIdx, noSrtRoutes int - if args.Paginator.Offset != nil { // save the offset in a varible to not duble check if we have offset and is still not 0 + if args.Paginator.Offset != nil { // save the offset in a variable to not double check if we have offset and is still not 0 startIdx = *args.Paginator.Offset } sortedRoutes = make(SortedRoutesList, 0, prfCount) @@ -725,13 +725,13 @@ func (rpS *RouteService) sortedRoutesForEvent(tnt string, args *ArgsGetRoutes) ( prfPag.Limit = &limit // add the limit to the paginator } } - if startIdx > 0 { // we have offest + if startIdx > 0 { // we have offset if idx := startIdx - len(rPrfl.Routes); idx >= 0 { // we still have offset so try the next profile startIdx = idx continue } // we have offset but is in the range of this profile - offset := startIdx // store in a seoarate var so when startIdx is updated the prfPag.Offset remains the same + offset := startIdx // store in a separate var so when startIdx is updated the prfPag.Offset remains the same startIdx = 0 // set it to 0 for the following loop prfPag.Offset = &offset } diff --git a/general_tests/routes_cases_it_test.go b/general_tests/routes_cases_it_test.go index 2885b2038..3a334dd35 100644 --- a/general_tests/routes_cases_it_test.go +++ b/general_tests/routes_cases_it_test.go @@ -66,6 +66,10 @@ var ( testV1RtsCasesSortingRoutesAllocateResources, testV1RtsCasesSortingRoutesReasNotAllRoutes, testV1RtsCasesSortingRoutesReasAllRoutes, + testV1RtsCasesRoutesProcessStatsForLoadRtsSorting, + testV1RtsCasesRoutesLoadRtsSorting, + testV1RtsCasesSortRoutesHigherCostV2V3, + //testV1RtsCasesSortRoutesHigherCostV1V3, testV1RtsCaseStopEngine, } ) @@ -310,7 +314,7 @@ func testV1RtsCaseGetRoutesAfterLoading(t *testing.T) { Tenant: "cgrates.org", FilterIDs: []string{"*string:~*req.Account:1005"}, Sorting: "*load", - SortingParameters: []string{"vendor1:3", "vendor2:1", "*default:2"}, + SortingParameters: []string{"vendor1:3", "*default:2"}, Routes: []*engine.Route{ { ID: "vendor1", @@ -319,6 +323,11 @@ func testV1RtsCaseGetRoutesAfterLoading(t *testing.T) { { ID: "vendor2", StatIDs: []string{"STATS_VENDOR_2:*sum#1"}, + Weight: 10, + }, + { + ID: "vendor3", + StatIDs: []string{"STATS_VENDOR_2:*distinct#~*req.Usage"}, }, }, } @@ -339,35 +348,36 @@ func testV1RtsCaseGetRoutesAfterLoading(t *testing.T) { // ROUTE_STATS1 expRt6 := &engine.RouteProfile{ - ID: "ROUTE_STATS1", + ID: "ROUTE_HC1", Tenant: "cgrates.org", FilterIDs: []string{"Fltr_tcc"}, - Sorting: "*qos", - SortingParameters: []string{"*tcc"}, + Sorting: "*hc", + SortingParameters: []string{}, Routes: []*engine.Route{ { - ID: "route1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - StatIDs: []string{"STATS_TCC1"}, - Weight: 10, + ID: "route1", + FilterIDs: []string{"*gte:~*resources.RES_GRP2.Available:6"}, + RatingPlanIDs: []string{"RP_VENDOR2"}, + ResourceIDs: []string{"RES_GRP2"}, + Weight: 20, }, { ID: "route2", - FilterIDs: []string{"*string:~*req.Account:1002"}, + FilterIDs: []string{"*gte:~*resources.RES_GRP1.TotalUsage:9"}, RatingPlanIDs: []string{"RP_VENDOR1"}, - StatIDs: []string{"STATS_TCC1"}, - Weight: 10, + ResourceIDs: []string{"RES_GRP1"}, + Weight: 20, }, { ID: "route3", RatingPlanIDs: []string{"RP_VENDOR1"}, - StatIDs: []string{"STATS_TCC2"}, - Weight: 20, + ResourceIDs: []string{"RES_GRP2"}, + Weight: 10, }, }, } if err := rtsCaseSv1Rpc.Call(utils.APIerSv1GetRouteProfile, - &utils.TenantID{ID: "ROUTE_STATS1", Tenant: "cgrates.org"}, + &utils.TenantID{ID: "ROUTE_HC1", Tenant: "cgrates.org"}, &reply); err != nil { t.Error(err) } else { @@ -668,10 +678,9 @@ func testV1RtsCasesSortingRoutesLCSetStatsAndResForMatching(t *testing.T) { Event: map[string]interface{}{ utils.AccountField: "1004", utils.Category: "vendor2", - //utils.ACD: "1m1s", - utils.Usage: "2m30s", - utils.AnswerTime: "2013-06-01T05:00:00Z", - utils.Cost: 1.0, + utils.Usage: "2m30s", + utils.AnswerTime: "2013-06-01T05:00:00Z", + utils.Cost: 1.0, }, }, } @@ -1007,12 +1016,13 @@ func testV1RtsCasesSortingRoutesQOS(t *testing.T) { { RouteID: "vendor2", SortingData: map[string]interface{}{ - utils.MetaACC: 1., - utils.MetaACD: 150., - "*sum#1": 3., - utils.MetaTCC: 3., - utils.MetaTCD: 450., - utils.Weight: 0., + utils.MetaACC: 1., + utils.MetaACD: 150., + "*sum#1": 3., + "*distinct#~*req.Usage": 1., + utils.MetaTCC: 3., + utils.MetaTCD: 450., + utils.Weight: 0., }, }, { @@ -1102,12 +1112,13 @@ func testV1RtsCasesSortingRoutesQOSAllRoutes(t *testing.T) { { RouteID: "vendor2", SortingData: map[string]interface{}{ - utils.MetaACC: 1., - utils.MetaACD: 150., - "*sum#1": 3., - utils.MetaTCC: 3., - utils.MetaTCD: 450., - utils.Weight: 0., + utils.MetaACC: 1., + utils.MetaACD: 150., + "*sum#1": 3., + "*distinct#~*req.Usage": 1., + utils.MetaTCC: 3., + utils.MetaTCD: 450., + utils.Weight: 0., }, }, }, @@ -1289,6 +1300,271 @@ func testV1RtsCasesSortingRoutesReasAllRoutes(t *testing.T) { } } +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 testV1RtsCasesSortRoutesHigherCostV1V3(t *testing.T) { + //to match route 1, RES_GRP2 must have *gte available 6 resources\ + var result string + evRs := &utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: utils.UUIDSha1Prefix(), + Event: map[string]interface{}{ + "Account": "1004"}, + }, + Units: 4, + } + 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) + } + + 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 testV1RtsCaseStopEngine(t *testing.T) { if err := engine.KillEngine(100); err != nil { t.Error(err)