From 1c2aac5547e90fc5de0b53459ba1892bbd0e3de2 Mon Sep 17 00:00:00 2001 From: armirveliaj Date: Wed, 21 Jan 2026 10:17:19 -0500 Subject: [PATCH] add test for resource & route --- routes/route_resource_sort_test.go | 301 +++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) diff --git a/routes/route_resource_sort_test.go b/routes/route_resource_sort_test.go index 4222c75d6..513b5c738 100644 --- a/routes/route_resource_sort_test.go +++ b/routes/route_resource_sort_test.go @@ -272,3 +272,304 @@ func TestPopulateResourcesForRoutesLazyPassErr(t *testing.T) { t.Errorf("Expected error <%v>, received <%v>", expErr, err) } } + +func TestResourceDescendentSorterSortRoutesNoResourceSConns(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cM := engine.NewConnManager(cfg) + rds := NewResourceDescendentSorter(cfg, cM) + + routes := map[string]*RouteWithWeight{} + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{}, + APIOpts: map[string]any{}, + } + extraOpts := &optsGetRoutes{} + + _, err := rds.SortRoutes(context.Background(), "PROFILE1", routes, ev, extraOpts) + errExpect := "MANDATORY_IE_MISSING: [connIDs]" + if err == nil || err.Error() != errExpect { + t.Errorf("Expected %v\n but received %v", errExpect, err) + } +} + +func TestResourceDescendentSorterSortRoutesNoResourceIDs(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.RouteSCfg().ResourceSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)} + cM := engine.NewConnManager(cfg) + rds := NewResourceDescendentSorter(cfg, cM) + + routes := map[string]*RouteWithWeight{ + "RW": { + Route: &utils.Route{}, + }, + } + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{}, + APIOpts: map[string]any{}, + } + extraOpts := &optsGetRoutes{} + + _, err := rds.SortRoutes(context.Background(), "PROFILE1", routes, ev, extraOpts) + errExpect := "MANDATORY_IE_MISSING: [ResourceIDs]" + if err == nil || err.Error() != errExpect { + t.Errorf("Expected %v\n but received %v", errExpect, err) + } +} + +func TestResourceDescendentSorterSortRoutesOK(t *testing.T) { + + defer func() { + engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil) + }() + + cfg := config.NewDefaultCGRConfig() + cfg.RouteSCfg().ResourceSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)} + + res1 := &utils.Resource{ + Tenant: "cgrates.org", + ID: "RSC1", + Usages: map[string]*utils.ResourceUsage{ + "RU1": { + ID: "RU1", + Units: 10, + }, + }, + } + res2 := &utils.Resource{ + Tenant: "cgrates.org", + ID: "RSC2", + Usages: map[string]*utils.ResourceUsage{ + "RU2": { + ID: "RU2", + Units: 5, + }, + }, + } + res3 := &utils.Resource{ + Tenant: "cgrates.org", + ID: "RSC3", + Usages: map[string]*utils.ResourceUsage{ + "RU3": { + ID: "RU3", + Units: 15, + }, + }, + } + + cc := make(chan birpc.ClientConnector, 1) + cc <- &ccMock{ + calls: map[string]func(ctx *context.Context, args any, reply any) error{ + utils.ResourceSv1GetResource: func(ctx *context.Context, args, reply any) error { + rplCast, canCast := reply.(*utils.Resource) + if !canCast { + t.Errorf("Wrong argument type : %T", reply) + return nil + } + argsCast := args.(*utils.TenantIDWithAPIOpts) + switch argsCast.ID { + case "RSC1": + *rplCast = *res1 + case "RSC2": + *rplCast = *res2 + case "RSC3": + *rplCast = *res3 + } + return nil + }, + }, + } + cM := engine.NewConnManager(cfg) + cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources), utils.ResourceSv1, cc) + + rds := NewResourceDescendentSorter(cfg, cM) + + routes := map[string]*RouteWithWeight{ + "RW1": { + Route: &utils.Route{ + ID: "Route1", + ResourceIDs: []string{"RSC1"}, + RouteParameters: "param1", + }, + Weight: 10, + }, + "RW2": { + Route: &utils.Route{ + ID: "Route2", + ResourceIDs: []string{"RSC2"}, + RouteParameters: "param2", + }, + Weight: 20, + }, + "RW3": { + Route: &utils.Route{ + ID: "Route3", + ResourceIDs: []string{"RSC3"}, + RouteParameters: "param3", + }, + Weight: 15, + blocker: true, + }, + } + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{}, + APIOpts: map[string]any{}, + } + extraOpts := &optsGetRoutes{} + + rcv, err := rds.SortRoutes(context.Background(), "PROFILE1", routes, ev, extraOpts) + if err != nil { + t.Fatal(err) + } + + if rcv.ProfileID != "PROFILE1" { + t.Errorf("Expected ProfileID <%s>, received <%s>", "PROFILE1", rcv.ProfileID) + } + + if rcv.Sorting != utils.MetaReds { + t.Errorf("Expected Sorting <%s>, received <%s>", utils.MetaReds, rcv.Sorting) + } + + if len(rcv.Routes) != 3 { + t.Fatalf("Expected 3 routes, received %d", len(rcv.Routes)) + } + + if rcv.Routes[0].RouteID != "Route3" { + t.Errorf("Expected first route to be Route3, got %s", rcv.Routes[0].RouteID) + } + if rcv.Routes[1].RouteID != "Route1" { + t.Errorf("Expected second route to be Route1, got %s", rcv.Routes[1].RouteID) + } + if rcv.Routes[2].RouteID != "Route2" { + t.Errorf("Expected third route to be Route2, got %s", rcv.Routes[2].RouteID) + } + + if _, hasBlocker := rcv.Routes[0].SortingData[utils.Blocker]; !hasBlocker { + t.Errorf("Expected Route3 to have blocker flag") + } +} + +func TestResourceDescendentSorterSortRoutesEmptyRoutes(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.RouteSCfg().ResourceSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)} + + cc := make(chan birpc.ClientConnector, 1) + cc <- &ccMock{ + calls: map[string]func(ctx *context.Context, args any, reply any) error{ + utils.ResourceSv1GetResource: func(ctx *context.Context, args, reply any) error { + return nil + }, + }, + } + cM := engine.NewConnManager(cfg) + cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources), utils.ResourceSv1, cc) + + rds := NewResourceDescendentSorter(cfg, cM) + + routes := map[string]*RouteWithWeight{} + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{}, + APIOpts: map[string]any{}, + } + extraOpts := &optsGetRoutes{} + + rcv, err := rds.SortRoutes(context.Background(), "PROFILE1", routes, ev, extraOpts) + if err != nil { + t.Fatal(err) + } + + if rcv.ProfileID != "PROFILE1" { + t.Errorf("Expected ProfileID <%s>, received <%s>", "PROFILE1", rcv.ProfileID) + } + + if rcv.Sorting != utils.MetaReds { + t.Errorf("Expected Sorting <%s>, received <%s>", utils.MetaReds, rcv.Sorting) + } + + if len(rcv.Routes) != 0 { + t.Errorf("Expected 0 routes, received %d", len(rcv.Routes)) + } +} + +func TestResourceDescendentSorterSortRoutesSingleRoute(t *testing.T) { + + defer func() { + engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil) + }() + + cfg := config.NewDefaultCGRConfig() + cfg.RouteSCfg().ResourceSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)} + + res := &utils.Resource{ + Tenant: "cgrates.org", + ID: "RSC1", + Usages: map[string]*utils.ResourceUsage{ + "RU1": { + ID: "RU1", + Units: 25, + }, + }, + } + + cc := make(chan birpc.ClientConnector, 1) + cc <- &ccMock{ + calls: map[string]func(ctx *context.Context, args any, reply any) error{ + utils.ResourceSv1GetResource: func(ctx *context.Context, args, reply any) error { + rplCast, canCast := reply.(*utils.Resource) + if !canCast { + t.Errorf("Wrong argument type : %T", reply) + return nil + } + *rplCast = *res + return nil + }, + }, + } + cM := engine.NewConnManager(cfg) + cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources), utils.ResourceSv1, cc) + + rds := NewResourceDescendentSorter(cfg, cM) + + routes := map[string]*RouteWithWeight{ + "RW": { + Route: &utils.Route{ + ID: "Route1", + ResourceIDs: []string{"RSC1"}, + RouteParameters: "param1", + }, + Weight: 50, + }, + } + ev := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{}, + APIOpts: map[string]any{}, + } + + exp := &SortedRoutes{ + ProfileID: "PROFILE1", + Sorting: utils.MetaReds, + Routes: []*SortedRoute{ + { + RouteID: "Route1", + RouteParameters: "param1", + SortingData: map[string]any{ + utils.ResourceUsageStr: 25.0, + utils.Weight: 50.0, + }, + }, + }, + } + + rcv, err := rds.SortRoutes(context.Background(), "PROFILE1", routes, ev, nil) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(rcv)) { + t.Errorf("Expected \n<%+v>,\n received \n<%+v>", utils.ToJSON(exp), utils.ToJSON(rcv)) + } +}