Files
cgrates/engine/routes_test.go
ionutboangiu 24d886c8e0 Pass CGRConfig to DataManager
instead of just CacheCfg. Prevents the need of global config var in
engine/datamanager.go
2025-03-10 13:49:34 +01:00

3062 lines
86 KiB
Go

/*
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 <http://www.gnu.org/licenses/>
*/
package engine
import (
"reflect"
"testing"
"time"
"github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
var (
testRoutesPrfs = []*RouteProfile{
{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
},
{
Tenant: "cgrates.org",
ID: "RouteProfile2",
FilterIDs: []string{"FLTR_SUPP_2"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route2",
Weights: utils.DynamicWeights{{Weight: 20}},
RouteParameters: "param2",
},
{
ID: "route3",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param3",
},
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 30}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 20}},
},
{
Tenant: "cgrates.org",
ID: "RouteProfilePrefix",
FilterIDs: []string{"FLTR_SUPP_3"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
},
}
testRoutesArgs = []*utils.CGREvent{
{ //matching RouteProfile1
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
{ //matching RouteProfile2
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile2",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
{ //matching RouteProfilePrefix
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfilePrefix",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
{ //matching
Tenant: "cgrates.org",
ID: "CGR",
Event: map[string]any{
"UsageInterval": "1s",
"PddInterval": "1s",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
)
func prepareRoutesData(t *testing.T, dm *DataManager) {
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_SUPP_2",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile2"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.PddInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"15.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_SUPP_3",
Rules: []*FilterRule{
{
Type: utils.MetaPrefix,
Element: "~*req.Route",
Values: []string{"RouteProfilePrefix"},
},
},
}, true); err != nil {
t.Fatal(err)
}
for _, spp := range testRoutesPrfs {
if err := dm.SetRouteProfile(context.Background(), spp, true); err != nil {
t.Fatal(err)
}
}
//Test each route profile from cache
for _, spp := range testRoutesPrfs {
if tempSpp, err := dm.GetRouteProfile(context.Background(), spp.Tenant,
spp.ID, true, true, utils.NonTransactional); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(spp, tempSpp) {
t.Fatalf("Expecting: %+v, received: %+v", spp, tempSpp)
}
}
}
func TestRoutesCache(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
prepareRoutesData(t, dmSPP)
}
func TestRoutesmatchingRouteProfilesForEvent(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
for i, spp := range testRoutesPrfs {
sprf, err := routeService.matchingRouteProfilesForEvent(context.Background(), testRoutesArgs[0].Tenant, testRoutesArgs[i])
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(spp, sprf[0].RouteProfile) {
t.Errorf("Expecting: %+v, received: %+v", spp, sprf[0].RouteProfile)
}
}
}
func TestRoutesSortedForEvent(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
eFirstRouteProfile := SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(10.0),
},
SortingData: map[string]any{
utils.Weight: 10.0,
},
RouteParameters: "param1",
},
},
}}
sprf, err := routeService.sortedRoutesForEvent(context.Background(), testRoutesArgs[0].Tenant, testRoutesArgs[0])
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
eFirstRouteProfile = SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(30.0),
},
SortingData: map[string]any{
utils.Weight: 30.0,
},
RouteParameters: "param1",
},
{
RouteID: "route2",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(20.0),
},
SortingData: map[string]any{
utils.Weight: 20.0,
},
RouteParameters: "param2",
},
{
RouteID: "route3",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(10.0),
},
SortingData: map[string]any{
utils.Weight: 10.0,
},
RouteParameters: "param3",
},
},
}}
sprf, err = routeService.sortedRoutesForEvent(context.Background(), testRoutesArgs[1].Tenant, testRoutesArgs[1])
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
eFirstRouteProfile = SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfilePrefix",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(10.0),
},
SortingData: map[string]any{
utils.Weight: 10.0,
},
RouteParameters: "param1",
},
},
}}
sprf, err = routeService.sortedRoutesForEvent(context.Background(), testRoutesArgs[2].Tenant, testRoutesArgs[2])
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
}
func TestRoutesSortedForEventWithLimit(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
eFirstRouteProfile := SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(30.0),
},
SortingData: map[string]any{
utils.Weight: 30.0,
},
RouteParameters: "param1",
},
{
RouteID: "route2",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(20.0),
},
SortingData: map[string]any{
utils.Weight: 20.0,
},
RouteParameters: "param2",
},
},
}}
args := testRoutesArgs[1].Clone()
args.APIOpts[utils.OptsRoutesLimit] = 2
sprf, err := routeService.sortedRoutesForEvent(context.Background(), args.Tenant, args)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
}
func TestRoutesSortedForEventWithOffset(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
eFirstRouteProfile := SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route3",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(10.0),
},
SortingData: map[string]any{
utils.Weight: 10.0,
},
RouteParameters: "param3",
},
},
}}
args := testRoutesArgs[1].Clone()
args.APIOpts[utils.OptsRoutesOffset] = 2
sprf, err := routeService.sortedRoutesForEvent(context.Background(), args.Tenant, args)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v,received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
}
func TestRoutesSortedForEventWithLimitAndOffset(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
eFirstRouteProfile := SortedRoutesList{&SortedRoutes{
ProfileID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route2",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(20.0),
},
SortingData: map[string]any{
utils.Weight: 20.0,
},
RouteParameters: "param2",
},
},
}}
args := testRoutesArgs[1].Clone()
args.APIOpts[utils.OptsRoutesLimit] = 1
args.APIOpts[utils.OptsRoutesOffset] = 1
sprf, err := routeService.sortedRoutesForEvent(context.Background(), args.Tenant, args)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v,received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
}
func TestRoutesNewOptsGetRoutes(t *testing.T) {
ev := &utils.CGREvent{
APIOpts: map[string]any{
utils.OptsRoutesMaxCost: 10,
utils.OptsRoutesIgnoreErrors: true,
},
}
spl := &optsGetRoutes{
ignoreErrors: true,
maxCost: 10.0,
paginator: &utils.Paginator{},
}
sprf, err := newOptsGetRoutes(context.Background(), ev, &FilterS{}, config.CgrConfig().RouteSCfg().Opts)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(spl, sprf) {
t.Errorf("Expecting: %+v,received: %+v", spl, sprf)
}
}
func TestRoutesNewOptsGetRoutesFromCfg(t *testing.T) {
config.CgrConfig().RouteSCfg().Opts.IgnoreErrors = []*config.DynamicBoolOpt{config.NewDynamicBoolOpt(nil, "", true, nil)}
ev := &utils.CGREvent{
APIOpts: map[string]any{},
}
spl := &optsGetRoutes{
ignoreErrors: true,
paginator: &utils.Paginator{},
}
sprf, err := newOptsGetRoutes(context.Background(), ev, &FilterS{}, config.CgrConfig().RouteSCfg().Opts)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(spl, sprf) {
t.Errorf("Expecting: %+v,received: %+v", spl, sprf)
}
}
func TestRoutesNewOptsGetRoutesIgnoreErrors(t *testing.T) {
ev := &utils.CGREvent{
APIOpts: map[string]any{
utils.OptsRoutesIgnoreErrors: true,
},
}
spl := &optsGetRoutes{
ignoreErrors: true,
paginator: &utils.Paginator{},
}
sprf, err := newOptsGetRoutes(context.Background(), ev, &FilterS{}, config.CgrConfig().RouteSCfg().Opts)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(spl, sprf) {
t.Errorf("Expecting: %+v,received: %+v", spl, sprf)
}
}
func TestRoutesMatchWithIndexFalse(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
cfg.RouteSCfg().IndexedSelects = false
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dmSPP)
for i, spp := range testRoutesPrfs {
sprf, err := routeService.matchingRouteProfilesForEvent(context.Background(), testRoutesArgs[0].Tenant, testRoutesArgs[i])
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(spp, sprf[0].RouteProfile) {
t.Errorf("Expecting: %+v, received: %+v", spp, sprf[0].RouteProfile)
}
}
}
func TestRoutesSortedForEventWithLimitAndOffset2(t *testing.T) {
Cache.Clear(nil)
sppTest := []*RouteProfile{
{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route2",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
},
{
Tenant: "cgrates.org",
ID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route2",
Weights: utils.DynamicWeights{{Weight: 20}},
RouteParameters: "param2",
},
{
ID: "route3",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param3",
},
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 30}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 5}},
},
{
Tenant: "cgrates.org",
ID: "RouteProfilePrefix",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 20}},
},
{
Tenant: "cgrates.org",
ID: "RouteProfilePrefix4",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{}},
},
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{},
APIOpts: map[string]any{utils.OptsRoutesProfilesCount: 3},
}
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
for _, spp := range sppTest {
if err := dmSPP.SetRouteProfile(context.Background(), spp, true); err != nil {
t.Errorf("Error: %+v", err)
}
if tempSpp, err := dmSPP.GetRouteProfile(context.Background(), spp.Tenant,
spp.ID, true, true, utils.NonTransactional); err != nil {
t.Errorf("Error: %+v", err)
} else if !reflect.DeepEqual(spp, tempSpp) {
t.Errorf("Expecting: %+v, received: %+v", spp, tempSpp)
}
}
eFirstRouteProfile := SortedRoutesList{
{
ProfileID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route2",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(10.),
},
SortingData: map[string]any{
utils.Weight: 10.,
},
RouteParameters: "param1",
},
},
},
{
ProfileID: "RouteProfile2",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
sortingDataDecimal: map[string]*utils.Decimal{
utils.Weight: utils.NewDecimalFromFloat64(30.),
},
SortingData: map[string]any{
utils.Weight: 30.,
},
RouteParameters: "param1",
},
},
},
}
args.APIOpts[utils.OptsRoutesLimit] = 2
args.APIOpts[utils.OptsRoutesOffset] = 1
sprf, err := routeService.sortedRoutesForEvent(context.Background(), args.Tenant, args)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(eFirstRouteProfile, sprf) {
t.Errorf("Expecting: %+v,received: %+v", utils.ToJSON(eFirstRouteProfile), utils.ToJSON(sprf))
}
}
func TestRoutesV1GetRoutesMsnStructFieldIDError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
var reply SortedRoutesList
args := &utils.CGREvent{
Tenant: "cgrates.org",
Event: map[string]any{},
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil || err.Error() != "MANDATORY_IE_MISSING: [ID]" {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "MANDATORY_IE_MISSING: [ID]", err)
}
}
func TestRoutesV1GetRoutesMsnStructFieldEventError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
var reply SortedRoutesList
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "CGREvent1",
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil || err.Error() != "MANDATORY_IE_MISSING: [Event]" {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "MANDATORY_IE_MISSING: [Event]", err)
}
}
func TestRoutesV1GetRoutesNotFoundError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
var reply SortedRoutesList
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "CGREvent1",
Event: map[string]any{},
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil || err.Error() != utils.NotFoundCaps {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.NotFoundCaps, err)
}
}
func TestRoutesV1GetRoutesNoTenantNotFoundError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dmSPP := NewDataManager(data, cfg, nil)
routeService := NewRouteService(dmSPP, &FilterS{
dm: dmSPP, cfg: cfg}, cfg, nil)
var reply SortedRoutesList
args := &utils.CGREvent{
ID: "CGREvent1",
Event: map[string]any{},
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil || err.Error() != utils.NotFoundCaps {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.NotFoundCaps, err)
}
}
func TestRoutesV1GetRoutesAttrConnError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
cfg.RPCConns()["testConn"] = config.NewDfltRPCConn()
cfg.RouteSCfg().AttributeSConns = []string{"testConn"}
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
connMng := NewConnManager(cfg)
dmSPP := NewDataManager(data, cfg, connMng)
routeService := NewRouteService(dmSPP, nil, cfg, connMng)
var reply SortedRoutesList
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "CGREvent1",
Event: map[string]any{},
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil || err.Error() != "ROUTES_ERROR:%!s(<nil>)" {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "ROUTES_ERROR:%!s(<nil>)", err)
}
}
func TestRoutesV1GetRouteProfilesForEventError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
connMng := NewConnManager(cfg)
dmSPP := NewDataManager(data, cfg, connMng)
fltr := &FilterS{dm: dmSPP, cfg: cfg}
routeService := NewRouteService(dmSPP, fltr, cfg, connMng)
var reply []*RouteProfile
args := &utils.CGREvent{
ID: "CGREvent1",
Event: map[string]any{},
}
err := routeService.V1GetRouteProfilesForEvent(context.Background(), args, &reply)
if err == nil || err.Error() != utils.NotFoundCaps {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.NotFoundCaps, err)
}
}
func TestRoutesV1GetRouteProfilesForEventMsnIDError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
connMng := NewConnManager(cfg)
dmSPP := NewDataManager(data, cfg, connMng)
fltr := &FilterS{dm: dmSPP, cfg: cfg}
routeService := NewRouteService(dmSPP, fltr, cfg, connMng)
var reply []*RouteProfile
args := &utils.CGREvent{
Tenant: "cgrates.org",
Event: map[string]any{},
}
err := routeService.V1GetRouteProfilesForEvent(context.Background(), args, &reply)
if err == nil || err.Error() != "MANDATORY_IE_MISSING: [ID]" {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "MANDATORY_IE_MISSING: [ID]", err)
}
}
func TestRoutesV1GetRouteProfilesForEventMsnEventError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
connMng := NewConnManager(cfg)
dmSPP := NewDataManager(data, cfg, connMng)
fltr := &FilterS{dm: dmSPP, cfg: cfg}
routeService := NewRouteService(dmSPP, fltr, cfg, connMng)
var reply []*RouteProfile
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "CGREvent1",
}
err := routeService.V1GetRouteProfilesForEvent(context.Background(), args, &reply)
if err == nil || err.Error() != "MANDATORY_IE_MISSING: [Event]" {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "MANDATORY_IE_MISSING: [Event]", err)
}
}
func TestRouteProfileSet(t *testing.T) {
rp := RouteProfile{}
exp := RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{Blocker: false},
},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
if err := rp.Set([]string{}, "", false); err != utils.ErrWrongPath {
t.Error(err)
}
if err := rp.Set([]string{"", ""}, "", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{"NotAField"}, "", false); err != utils.ErrWrongPath {
t.Error(err)
}
if err := rp.Set([]string{"NotAField", "1"}, ":", false); err != utils.ErrWrongPath {
t.Error(err)
}
if err := rp.Set([]string{utils.Tenant}, "cgrates.org", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.ID}, "ID", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.FilterIDs}, "fltr1;*string:~*req.Account:1001", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Weights}, ";0", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Blockers}, ";false", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Sorting}, utils.MetaQOS, false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.SortingParameters}, "param", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.ID}, "RT1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.FilterIDs}, "fltr1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.AccountIDs}, "acc1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.RateProfileIDs}, "rp1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.ResourceIDs}, "res1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.StatIDs}, "stat1", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.Weights}, ";0", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.Blockers}, ";true", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, utils.RouteParameters}, "params", false); err != nil {
t.Error(err)
}
if err := rp.Set([]string{utils.SortingParameters, "wrong"}, "param", false); err != utils.ErrWrongPath {
t.Error(err)
}
if err := rp.Set([]string{utils.Routes, "wrong"}, "param", false); err != utils.ErrWrongPath {
t.Error(err)
}
if !reflect.DeepEqual(exp, rp) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(rp))
}
}
func TestRouteProfileAsInterface(t *testing.T) {
rp := RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{{Blocker: false}},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
if _, err := rp.FieldAsInterface(nil); err != utils.ErrNotFound {
t.Fatal(err)
}
if _, err := rp.FieldAsInterface([]string{"field"}); err != utils.ErrNotFound {
t.Fatal(err)
}
if _, err := rp.FieldAsInterface([]string{"field", ""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if val, err := rp.FieldAsInterface([]string{utils.Tenant}); err != nil {
t.Fatal(err)
} else if exp := "cgrates.org"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.ID}); err != nil {
t.Fatal(err)
} else if exp := utils.ID; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Weights}); err != nil {
t.Fatal(err)
} else if exp := ";0"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Blockers}); err != nil {
t.Fatal(err)
} else if exp := ";false"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.FilterIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.FilterIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.FilterIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.FilterIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.SortingParameters}); err != nil {
t.Fatal(err)
} else if exp := rp.SortingParameters; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.SortingParameters + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.SortingParameters[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Sorting}); err != nil {
t.Fatal(err)
} else if exp := rp.Sorting; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if _, err := rp.FieldAsInterface([]string{utils.Routes + "[4]", ""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if _, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", ""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if _, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", "", ""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.ID}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].ID; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.Weights}); err != nil {
t.Fatal(err)
} else if exp := ";0"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.Blockers}); err != nil {
t.Fatal(err)
} else if exp := ";true"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.RouteParameters}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].RouteParameters; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.FilterIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].FilterIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.FilterIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].FilterIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.AccountIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].AccountIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.AccountIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].AccountIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.RateProfileIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].RateProfileIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.RateProfileIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].RateProfileIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.ResourceIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].ResourceIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.ResourceIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].ResourceIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.StatIDs}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].StatIDs; !reflect.DeepEqual(exp, val) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, err := rp.FieldAsInterface([]string{utils.Routes + "[0]", utils.StatIDs + "[0]"}); err != nil {
t.Fatal(err)
} else if exp := rp.Routes[0].StatIDs[0]; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if _, err := rp.FieldAsString([]string{""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if val, err := rp.FieldAsString([]string{utils.ID}); err != nil {
t.Fatal(err)
} else if exp := "ID"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, exp := rp.String(), utils.ToJSON(rp); exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if _, err := rp.Routes[0].FieldAsString([]string{""}); err != utils.ErrNotFound {
t.Fatal(err)
}
if val, err := rp.Routes[0].FieldAsString([]string{utils.ID}); err != nil {
t.Fatal(err)
} else if exp := "RT1"; exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
if val, exp := rp.Routes[0].String(), utils.ToJSON(rp.Routes[0]); exp != val {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(val))
}
}
func TestRouteProfileMerge(t *testing.T) {
dp := &RouteProfile{}
exp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
if dp.Merge(&RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}); !reflect.DeepEqual(exp, dp) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(dp))
}
}
func TestRouteMerge(t *testing.T) {
route := &Route{}
routeV2 := &Route{
ID: "RouteId",
RouteParameters: "RouteParam",
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: false}},
FilterIDs: []string{"FltrId"},
AccountIDs: []string{"AccId"},
RateProfileIDs: []string{"RateProfileId"},
ResourceIDs: []string{"ResourceId"},
StatIDs: []string{"StatId"},
}
exp := routeV2
route.Merge(routeV2)
if !reflect.DeepEqual(route, exp) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(route))
}
}
func TestRouteProfileCompileCacheParametersErrParse(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
Cache.Clear(nil)
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaLoad,
SortingParameters: []string{"sort:param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
expErr := `strconv.Atoi: parsing "param": invalid syntax`
if err := rp.compileCacheParameters(); err.Error() != expErr || err == nil {
t.Errorf("Expected error <%v>, Received error <%v>", expErr, err)
}
}
func TestRouteProfileCompileCacheParametersConfigRatio(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
Cache.Clear(nil)
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaLoad,
SortingParameters: []string{"param:1"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
expErr := `strconv.Atoi: parsing "param": invalid syntax`
if err := rp.compileCacheParameters(); err != nil {
t.Errorf("Expected error <%v>, Received error <%v>", expErr, err)
}
}
func TestRouteProfileCompileCacheParametersDefaultRatio(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
Cache.Clear(nil)
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaLoad,
SortingParameters: []string{"*default:1"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
expErr := `strconv.Atoi: parsing "param": invalid syntax`
if err := rp.compileCacheParameters(); err != nil {
t.Errorf("Expected error <%v>, Received error <%v>", expErr, err)
}
}
func TestRouteProfileCompileCacheParametersRouteRatio(t *testing.T) {
tmp := Cache
defer func() {
Cache = tmp
}()
Cache.Clear(nil)
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaLoad,
SortingParameters: []string{"RT1:1"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
expErr := `strconv.Atoi: parsing "param": invalid syntax`
if err := rp.compileCacheParameters(); err != nil {
t.Errorf("Expected error <%v>, Received error <%v>", expErr, err)
}
}
func TestRouteSV1GetRoutesListErr(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
connMng := NewConnManager(cfg)
dmSPP := NewDataManager(data, cfg, connMng)
fltr := &FilterS{dm: dmSPP, cfg: cfg}
var reply *[]string
rpS := NewRouteService(dmSPP, fltr, cfg, connMng)
if err := rpS.V1GetRoutesList(context.Background(), testRoutesArgs[3], reply); err != utils.ErrNotFound {
t.Errorf("Expected error <%v>, Received error <%v>", utils.ErrNotFound, err)
}
}
func TestRouteSMatchingRouteProfilesForEventGetRouteProfileErr1(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cM := NewConnManager(cfg)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
ev := []*utils.CGREvent{
{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
prepareRoutesData(t, dm)
if err := Cache.Set(context.Background(), utils.CacheRouteProfiles, "cgrates.org:RouteProfile1", nil, []string{}, true, utils.NonTransactional); err != nil {
t.Error(err)
}
if _, err := rpS.matchingRouteProfilesForEvent(context.Background(), "cgrates.org", ev[0]); err != utils.ErrNotFound {
t.Errorf("Expected error <%v>, Received error <%v>", utils.ErrNotFound, err)
}
}
func TestRouteSMatchingRouteProfilesForEventGetRouteProfileErr2(t *testing.T) {
cfgtmp := config.CgrConfig()
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
config.SetCgrConfig(cfgtmp)
}()
cfg := config.NewDefaultCGRConfig()
cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
cfg.CacheCfg().Partitions[utils.CacheRouteProfiles].Replicate = true
config.SetCgrConfig(cfg)
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cc := make(chan birpc.ClientConnector, 1)
cc <- &ccMock{
calls: map[string]func(ctx *context.Context, args any, reply any) error{
utils.CacheSv1ReplicateSet: func(ctx *context.Context, args, reply any) error { return utils.ErrNotImplemented },
},
}
cM := NewConnManager(cfg)
cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator), utils.CacheSv1, cc)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
ev := []*utils.CGREvent{
{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
Cache = NewCacheS(cfg, dm, cM, nil)
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetRouteProfile(context.Background(), testRoutesPrfs[0], true); err != nil {
t.Fatal(err)
}
if _, err := rpS.matchingRouteProfilesForEvent(context.Background(), "cgrates.org", ev[0]); err != utils.ErrNotImplemented {
t.Errorf("Expected error <%v>, Received error <%v>", utils.ErrNotImplemented, err)
}
}
func TestRouteSMatchingRouteProfilesForEventPassErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cM := NewConnManager(cfg)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
ev := []*utils.CGREvent{
{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: "bad input",
Element: "bad input",
Values: []string{"bad input"},
},
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetRouteProfile(context.Background(), testRoutesPrfs[0], true); err != nil {
t.Fatal(err)
}
expErr := "NOT_IMPLEMENTED:bad input"
if _, err := rpS.matchingRouteProfilesForEvent(context.Background(), "cgrates.org", ev[0]); err == nil || err.Error() != expErr {
t.Errorf("Expected error <%v>, received <%v>", expErr, err)
}
}
func TestRouteSMatchingRPSForEventWeightFromDynamicsErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cM := NewConnManager(cfg)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
ev := []*utils.CGREvent{
{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
rprof := []*RouteProfile{
{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: []string{"*stirng:~*req.Account:1001"},
Weight: 10,
},
},
}}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetRouteProfile(context.Background(), rprof[0], true); err != nil {
t.Fatal(err)
}
expErr := "NOT_IMPLEMENTED:*stirng"
_, err := rpS.matchingRouteProfilesForEvent(context.Background(), "cgrates.org", ev[0])
if err == nil || err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestRouteSMatchingRPSForEventBlockerFromDynamicsErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cM := NewConnManager(cfg)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
ev := []*utils.CGREvent{
{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
rprof := []*RouteProfile{
{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
Blockers: utils.DynamicBlockers{
{
FilterIDs: []string{"*stirng:~*req.Account:1001"},
Blocker: false,
},
},
}}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetRouteProfile(context.Background(), rprof[0], true); err != nil {
t.Fatal(err)
}
expErr := "NOT_IMPLEMENTED:*stirng"
_, err := rpS.matchingRouteProfilesForEvent(context.Background(), "cgrates.org", ev[0])
if err == nil || err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestNewOptsGetRoutesGetBoolOptsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.IgnoreErrors = []*config.DynamicBoolOpt{
config.NewDynamicBoolOpt([]string{"*string.invalid:filter"}, "cgrates.org", false, nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "TestEvent",
Event: map[string]any{
utils.AccountField: 1001,
},
APIOpts: map[string]any{},
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := newOptsGetRoutes(context.Background(), ev, fS, cfg.RouteSCfg().Opts)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestNewOptsGetRoutesGetIntPointerOptsLimitErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.Limit = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt([]string{"*string.invalid:filter"}, "cgrates.org", utils.IntPointer(4), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "TestEvent",
Event: map[string]any{
utils.AccountField: 1001,
},
APIOpts: map[string]any{},
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := newOptsGetRoutes(context.Background(), ev, fS, cfg.RouteSCfg().Opts)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestNewOptsGetRoutesGetIntPointerOptsOffsetErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.Offset = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt([]string{"*string.invalid:filter"}, "cgrates.org", utils.IntPointer(4), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "TestEvent",
Event: map[string]any{
utils.AccountField: 1001,
},
APIOpts: map[string]any{},
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := newOptsGetRoutes(context.Background(), ev, fS, cfg.RouteSCfg().Opts)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestNewOptsGetRoutesGetIntPointerOptsMaxItemsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.MaxItems = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt([]string{"*string.invalid:filter"}, "cgrates.org", utils.IntPointer(4), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "TestEvent",
Event: map[string]any{
utils.AccountField: 1001,
},
APIOpts: map[string]any{},
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := newOptsGetRoutes(context.Background(), ev, fS, cfg.RouteSCfg().Opts)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestNewOptsGetRoutesGetInterfaceOptsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.MaxCost = []*config.DynamicInterfaceOpt{
{
FilterIDs: []string{"*string.invalid:filter"},
Tenant: "cgrates.org",
Value: 2,
},
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "TestEvent",
Event: map[string]any{
utils.AccountField: 1001,
},
APIOpts: map[string]any{},
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := newOptsGetRoutes(context.Background(), ev, fS, cfg.RouteSCfg().Opts)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestSortedRoutesForEventsortedRoutesForProfileErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.ProfileCount = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt([]string{"*string.invalid:filter"}, "cgrates.org", utils.IntPointer(4), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
expErr := `unsupported sorting strategy: *weight`
_, err := routeService.sortedRoutesForEvent(context.Background(), ev.Tenant, ev)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestSortedRoutesForEventGetIntPointerOptsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.ProfileCount = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt([]string{"*string.invalid:filter"}, "cgrates.org", utils.IntPointer(4), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := routeService.sortedRoutesForEvent(context.Background(), ev.Tenant, ev)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestSortedRoutesForEventNewOptsGetRoutesErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.IgnoreErrors = []*config.DynamicBoolOpt{
config.NewDynamicBoolOpt([]string{"*string.invalid:filter"}, "cgrates.org", false, nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
expErr := `inline parse error for string: <*string.invalid:filter>`
_, err := routeService.sortedRoutesForEvent(context.Background(), ev.Tenant, ev)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestSortedRoutesForEventExceedMaxItemsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.MaxItems = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt(nil, "cgrates.org", utils.IntPointer(1), nil),
}
cfg.RouteSCfg().Opts.Limit = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt(nil, "cgrates.org", utils.IntPointer(2), nil),
}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
expErr := `SERVER_ERROR: maximum number of items exceeded`
_, err := routeService.sortedRoutesForEvent(context.Background(), ev.Tenant, ev)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestRouteSV1GetRoutesGetStringOptsErr(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.Context = []*config.DynamicStringOpt{
config.NewDynamicStringOpt([]string{"*string.invalid:filter"}, "cgrates.org", "value2", nil),
}
cfg.RouteSCfg().AttributeSConns = []string{"testConn"}
dataDB := NewInternalDB(nil, nil, nil)
dm := NewDataManager(dataDB, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
ev := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{},
}
var reply *SortedRoutesList
expErr := `inline parse error for string: <*string.invalid:filter>`
err := routeService.V1GetRoutes(context.Background(), ev, reply)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestRoutesV1GetRoutesCallWithAlteredFields(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
cfg.RPCConns()["testConn"] = config.NewDfltRPCConn()
cfg.RouteSCfg().AttributeSConns = []string{utils.ConcatenatedKey(utils.MetaInternal,
utils.MetaAttributes)}
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cc := make(chan birpc.ClientConnector, 1)
cc <- &ccMock{
calls: map[string]func(ctx *context.Context, args any, reply any) error{
utils.AttributeSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
*reply.(*AttrSProcessEventReply) = AttrSProcessEventReply{
AlteredFields: []*FieldsAltered{{
Fields: []string{utils.AccountField},
}},
CGREvent: &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
},
}
return nil
},
},
}
cM := NewConnManager(cfg)
cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes), utils.AttributeSv1, cc)
dm := NewDataManager(data, cfg, cM)
fS := NewFilterS(cfg, cM, dm)
routeService := NewRouteService(dm, fS, cfg, cM)
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
var reply SortedRoutesList
exp := SortedRoutesList{
{
ProfileID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*SortedRoute{
{
RouteID: "route1",
RouteParameters: "param1",
SortingData: map[string]any{
"Weight": 10,
},
},
},
},
}
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err != nil {
t.Error(err)
} else if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(reply)) {
t.Errorf("Expected error <%+v>, received error <%+v>", utils.ToJSON(exp), utils.ToJSON(reply))
}
}
func TestRoutesV1GetRoutesSortedRoutesForEventErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.ProfileCount = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt(nil, "cgrates.org", utils.IntPointer(4), nil),
}
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
var reply SortedRoutesList
expErr := `SERVER_ERROR: unsupported sorting strategy: *weight`
err := routeService.V1GetRoutes(context.Background(), args, &reply)
if err == nil ||
err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestV1GetRouteProfilesForEventMatchingRouteProfErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
cM := NewConnManager(cfg)
dm := NewDataManager(data, cfg, cM)
fltrS := NewFilterS(cfg, cM, dm)
rpS := NewRouteService(dm, fltrS, cfg, cM)
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
if err := dm.SetFilter(context.Background(), &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RPP_1",
Rules: []*FilterRule{
{
Type: "bad input",
Element: "bad input",
Values: []string{"bad input"},
},
{
Type: utils.MetaString,
Element: "~*req.Route",
Values: []string{"RouteProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{time.Second.String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}, true); err != nil {
t.Fatal(err)
}
if err := dm.SetRouteProfile(context.Background(), testRoutesPrfs[0], true); err != nil {
t.Fatal(err)
}
var reply []*RouteProfile
expErr := "SERVER_ERROR: NOT_IMPLEMENTED:bad input"
err := rpS.V1GetRouteProfilesForEvent(context.Background(), args, &reply)
if err == nil || err.Error() != expErr {
t.Errorf("Expected error <%v>, received <%v>", expErr, err)
}
}
func TestV1GetRouteProfilesForEventOK(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().StringIndexedFields = nil
cfg.RouteSCfg().PrefixIndexedFields = nil
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
rpS := NewRouteService(dm, &FilterS{
dm: dm, cfg: cfg}, cfg, nil)
prepareRoutesData(t, dm)
exp := []*RouteProfile{
{
Tenant: "cgrates.org",
ID: "RouteProfile1",
FilterIDs: []string{"FLTR_RPP_1"},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
},
}
var reply []*RouteProfile
err := rpS.V1GetRouteProfilesForEvent(context.Background(), testRoutesArgs[0], &reply)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(utils.ToJSON(reply), utils.ToJSON(exp)) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(exp), utils.ToJSON(reply))
}
}
func TestRoutessortedRoutesForProfileLazyPassErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
FilterIDs: []string{"bad fltr"},
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
pag := utils.Paginator{}
extraOpts := &optsGetRoutes{}
expErr := "NOT_FOUND:bad fltr"
if _, err := routeService.sortedRoutesForProfile(context.Background(), "cgrates.org", rp, args, pag, extraOpts); err == nil || err.Error() != expErr {
t.Errorf("Expected error <%v>, Received error <%v> ", expErr, err.Error())
}
}
func TestRoutessortedRoutesForProfileLazyPassFalse(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
sorter: RouteSortDispatcher{
utils.MetaWeight: NewWeightSorter(cfg),
},
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
FilterIDs: []string{"*string:~*req.Account:1010", "*string:~*vars.Field1:Val1"},
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
pag := utils.Paginator{}
extraOpts := &optsGetRoutes{}
exp := SortedRoutes{
ProfileID: "RouteProfile1",
Sorting: "*weight",
Routes: []*SortedRoute{},
}
if rcv, err := routeService.sortedRoutesForProfile(context.Background(), "cgrates.org", rp, args, pag, extraOpts); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(rcv)) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(exp), utils.ToJSON(rcv))
}
}
func TestRoutessortedRoutesForProfileWeightFromDynamicsErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{
{
FilterIDs: []string{"*stirng:~*req.Account:1001"},
Weight: 10,
},
},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
pag := utils.Paginator{}
extraOpts := &optsGetRoutes{}
expErr := "NOT_IMPLEMENTED:*stirng"
_, err := routeService.sortedRoutesForProfile(context.Background(), "cgrates.org", rp, args, pag, extraOpts)
if err == nil || err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestRoutessortedRoutesForProfileBlockerFromDynamicsErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := &RouteS{
dm: dm,
fltrS: fS,
cfg: cfg,
connMgr: nil,
}
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
Blockers: utils.DynamicBlockers{
{
FilterIDs: []string{"*stirng:~*req.Account:1001"},
Blocker: false,
},
},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
pag := utils.Paginator{}
extraOpts := &optsGetRoutes{}
expErr := "NOT_IMPLEMENTED:*stirng"
_, err := routeService.sortedRoutesForProfile(context.Background(), "cgrates.org", rp, args, pag, extraOpts)
if err == nil || err.Error() != expErr {
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
}
}
func TestRoutessortedRoutesForProfileSortHasBlocker(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := NewRouteService(dm, fS, cfg, nil)
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
pag := utils.Paginator{}
extraOpts := &optsGetRoutes{}
exp := SortedRoutes{
ProfileID: "RouteProfile1",
Sorting: "*weight",
Routes: []*SortedRoute{
{
RouteID: "route1",
RouteParameters: "param1",
SortingData: map[string]any{utils.Blocker: true, utils.Weight: 10}},
},
}
if rcv, err := routeService.sortedRoutesForProfile(context.Background(), "cgrates.org", rp, args, pag, extraOpts); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(rcv)) {
t.Errorf("Expecting: \n%+v,\n received: \n%+v", utils.ToJSON(exp), utils.ToJSON(rcv))
}
}
func TestRoutessortedRoutesForEventNoSortedRoutesErr(t *testing.T) {
defer func() {
Cache = NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()
cfg := config.NewDefaultCGRConfig()
cfg.RouteSCfg().Opts.Offset = []*config.DynamicIntPointerOpt{
config.NewDynamicIntPointerOpt(nil, "cgrates.org", utils.IntPointer(10), nil),
}
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := NewRouteService(dm, fS, cfg, nil)
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
_, err := routeService.sortedRoutesForEvent(context.Background(), "cgrates.org", args)
if err != utils.ErrNotFound {
t.Errorf("Expected error <%+v>, received error <%+v>", utils.ErrNotFound, err)
}
}
func TestRouteSV1GetRoutesListOK(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, cfg.DataDbCfg().Items)
dm := NewDataManager(data, cfg, nil)
fS := NewFilterS(cfg, nil, dm)
routeService := NewRouteService(dm, fS, cfg, nil)
args := &utils.CGREvent{
Tenant: "cgrates.org",
ID: "utils.CGREvent1",
Event: map[string]any{
"Route": "RouteProfile1",
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
"UsageInterval": "1s",
"PddInterval": "1s",
utils.Weight: "20.0",
},
APIOpts: map[string]any{
utils.OptsRoutesProfilesCount: 1,
},
}
rp := &RouteProfile{
Tenant: "cgrates.org",
ID: "RouteProfile1",
Sorting: utils.MetaWeight,
Routes: []*Route{
{
ID: "route1",
Weights: utils.DynamicWeights{{Weight: 10}},
RouteParameters: "param1",
},
},
Weights: utils.DynamicWeights{{Weight: 10}},
Blockers: utils.DynamicBlockers{{Blocker: true}},
}
if err := dm.SetRouteProfile(context.Background(), rp, true); err != nil {
t.Fatal(err)
}
exp := []string{"route1:param1"}
var reply []string
err := routeService.V1GetRoutesList(context.Background(), args, &reply)
if err != nil {
t.Error(err)
} else if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(reply)) {
t.Errorf("Expecting: \n%+v,\n received: \n%+v", utils.ToJSON(exp), utils.ToJSON(reply))
}
}
func TestRouteProfileMergeWithRPRoutes(t *testing.T) {
dp := &RouteProfile{
Routes: []*Route{
{
ID: "RT1",
},
},
}
exp := &RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}
if dp.Merge(&RouteProfile{
Tenant: "cgrates.org",
ID: "ID",
FilterIDs: []string{"fltr1", "*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{{}},
Sorting: utils.MetaQOS,
SortingParameters: []string{"param"},
Routes: []*Route{{
ID: "RT1",
FilterIDs: []string{"fltr1"},
AccountIDs: []string{"acc1"},
RateProfileIDs: []string{"rp1"},
ResourceIDs: []string{"res1"},
StatIDs: []string{"stat1"},
Weights: utils.DynamicWeights{{}},
Blockers: utils.DynamicBlockers{
{
Blocker: true,
},
},
RouteParameters: "params",
}},
}); !reflect.DeepEqual(exp, dp) {
t.Errorf("Expected %v \n but received \n %v", utils.ToJSON(exp), utils.ToJSON(dp))
}
}