mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
1638 lines
44 KiB
Go
1638 lines
44 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
/*
|
|
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
|
Copyright (C) ITsysCOM GmbH
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
package general_tests
|
|
|
|
import (
|
|
"path"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cgrates/birpc"
|
|
"github.com/cgrates/birpc/context"
|
|
"github.com/cgrates/cgrates/config"
|
|
"github.com/cgrates/cgrates/engine"
|
|
"github.com/cgrates/cgrates/utils"
|
|
)
|
|
|
|
var (
|
|
rtsCaseSv1CfgPath string
|
|
rtsCaseSv1Cfg *config.CGRConfig
|
|
rtsCaseSv1Rpc *birpc.Client
|
|
rtsCasePrf *engine.RouteWithAPIOpts
|
|
rtsCaseSv1ConfDIR string //run tests for specific configuration
|
|
|
|
sTestsRtsCaseSV1 = []func(t *testing.T){
|
|
testV1RtsCaseLoadConfig,
|
|
testV1RtsCaseInitDataDb,
|
|
testV1RtsCaseResetStorDb,
|
|
testV1RtsCaseStartEngine,
|
|
testV1RtsCaseRpcConn,
|
|
testV1RtsCaseFromFolder,
|
|
testV1RtsCaseGetRoutesAfterLoading,
|
|
testV1RtsCasesSortingRoutesWeightAccountValue,
|
|
testV1RtsCasesSortingRoutesWeightAllRoutes,
|
|
testV1RtsCasesSortingRoutesWeightNotMatchingValue,
|
|
testV1RtsCasesSortingRoutesLowestCost,
|
|
testV1RtsCasesSortingRoutesLowestCostDefaultUsage,
|
|
testV1RtsCasesSortingRoutesLCSetStatsAndResForMatching,
|
|
testV1RtsCasesSortingRoutesLowestCostStats,
|
|
testV1RtsCasesSortingRoutesLowestCosMatchingAllRoutes,
|
|
testV1RtsCasesSortingRoutesLowestCosMaxCost,
|
|
testV1RtsCasesSortingRoutesLowestCosMaxCostNotMatch,
|
|
testV1RtsCasesSortingRoutesProcessMetrics,
|
|
testV1RtsCasesSortingRoutesQOS,
|
|
testV1RtsCasesSortingRoutesQOSAllRoutes,
|
|
testV1RtsCasesSortingRoutesQOSNotFound,
|
|
testV1RtsCasesSortingRoutesAllocateResources,
|
|
testV1RtsCasesSortingRoutesReasNotAllRoutes,
|
|
testV1RtsCasesSortingRoutesReasAllRoutes,
|
|
testV1RtsCasesRoutesProcessStatsForLoadRtsSorting,
|
|
testV1RtsCasesRoutesLoadRtsSorting,
|
|
testV1RtsCasesSortRoutesHigherCostV2V3,
|
|
testV1RtsCasesSortRoutesHigherCostAllocateRes,
|
|
testV1RtsCasesSortRoutesHigherCostV1V3,
|
|
testV1RtsCasesSortRoutesHigherCostAllRoutes,
|
|
testV1RtsCaseStopEngine,
|
|
}
|
|
)
|
|
|
|
// Test start here
|
|
func TestRoutesCaseV1IT(t *testing.T) {
|
|
switch *utils.DBType {
|
|
case utils.MetaInternal:
|
|
rtsCaseSv1ConfDIR = "tutinternal"
|
|
case utils.MetaMySQL:
|
|
rtsCaseSv1ConfDIR = "tutmysql"
|
|
case utils.MetaMongo:
|
|
rtsCaseSv1ConfDIR = "tutmongo"
|
|
case utils.MetaPostgres:
|
|
t.SkipNow()
|
|
default:
|
|
t.Fatal("Unknown Database type")
|
|
}
|
|
for _, stest := range sTestsRtsCaseSV1 {
|
|
t.Run(rtsCaseSv1ConfDIR, stest)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCaseLoadConfig(t *testing.T) {
|
|
var err error
|
|
rtsCaseSv1CfgPath = path.Join(*utils.DataDir, "conf", "samples", rtsCaseSv1ConfDIR)
|
|
if rtsCaseSv1Cfg, err = config.NewCGRConfigFromPath(rtsCaseSv1CfgPath); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCaseInitDataDb(t *testing.T) {
|
|
if err := engine.InitDataDB(rtsCaseSv1Cfg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Wipe out the cdr database
|
|
func testV1RtsCaseResetStorDb(t *testing.T) {
|
|
if err := engine.InitStorDb(rtsCaseSv1Cfg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCaseStartEngine(t *testing.T) {
|
|
if _, err := engine.StopStartEngine(rtsCaseSv1CfgPath, *utils.WaitRater); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCaseRpcConn(t *testing.T) {
|
|
rtsCaseSv1Rpc = engine.NewRPCClient(t, rtsCaseSv1Cfg.ListenCfg())
|
|
}
|
|
|
|
func testV1RtsCaseFromFolder(t *testing.T) {
|
|
var reply string
|
|
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*utils.DataDir, "tariffplans", "tutroutes")}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1LoadTariffPlanFromFolder, attrs, &reply); err != nil {
|
|
t.Error(err)
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
|
|
func testV1RtsCaseGetRoutesAfterLoading(t *testing.T) {
|
|
// ROUTE_ACNT_1001
|
|
expRt1 := &engine.RouteProfile{
|
|
ID: "ROUTE_ACNT_1001",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"*string:~*req.Account:1001"},
|
|
Sorting: "*weight",
|
|
SortingParameters: []string{},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "vendor1",
|
|
FilterIDs: []string{"FLTR_DEST_1003"},
|
|
Weight: 10,
|
|
},
|
|
{
|
|
ID: "vendor2",
|
|
FilterIDs: []string{"*gte:~*accounts.1001.BalanceMap.*monetary[0].Value:10"},
|
|
Weight: 20,
|
|
},
|
|
{
|
|
ID: "vendor3",
|
|
FilterIDs: []string{"FLTR_DEST_1003", "*prefix:~*req.Account:10"},
|
|
Weight: 40,
|
|
},
|
|
{
|
|
ID: "vendor4",
|
|
Weight: 35,
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.RouteProfile
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_ACNT_1001", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
if !reflect.DeepEqual(expRt1, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt1), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
// ROUTE_ACNT_1002
|
|
expRt2 := &engine.RouteProfile{
|
|
ID: "ROUTE_ACNT_1002",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"*string:~*req.Account:1002"},
|
|
Sorting: "*lc",
|
|
SortingParameters: []string{},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "vendor1",
|
|
FilterIDs: []string{"*lte:~*resources.RES_GRP1.TotalUsage:5"},
|
|
RatingPlanIDs: []string{"RP_VENDOR1"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor2",
|
|
FilterIDs: []string{"*gte:~*stats.STATS_VENDOR_2.*acd:1m"},
|
|
RatingPlanIDs: []string{"RP_VENDOR2"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor3",
|
|
RatingPlanIDs: []string{"RP_VENDOR2"},
|
|
Weight: 10,
|
|
},
|
|
{
|
|
ID: "vendor4",
|
|
FilterIDs: []string{"*ai:~*req.AnswerTime:2013-06-01T00:00:00Z|2013-06-01T10:00:00Z"},
|
|
RatingPlanIDs: []string{"RP_STANDARD"},
|
|
Weight: 30,
|
|
},
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_ACNT_1002", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
if !reflect.DeepEqual(expRt2, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt2), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
// ROUTE_ACNT_1003
|
|
expRt3 := &engine.RouteProfile{
|
|
ID: "ROUTE_ACNT_1003",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"*string:~*req.Account:1003"},
|
|
Sorting: "*qos",
|
|
SortingParameters: []string{"*acd", "*tcc"},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "vendor1",
|
|
StatIDs: []string{"STATS_VENDOR_1"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor2",
|
|
FilterIDs: []string{"*prefix:~*req.Destination:10"},
|
|
StatIDs: []string{"STATS_VENDOR_2"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor3",
|
|
FilterIDs: []string{"*gte:~*stats.STATS_VENDOR_1.*tcc:6"},
|
|
StatIDs: []string{"STATS_VENDOR_1"},
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_ACNT_1003", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
sort.Strings(reply.SortingParameters)
|
|
sort.Strings(expRt1.SortingParameters)
|
|
if !reflect.DeepEqual(expRt3, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt3), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
// ROUTE_ACNT_1004
|
|
expRt4 := &engine.RouteProfile{
|
|
ID: "ROUTE_ACNT_1004",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"*string:~*req.Account:1004"},
|
|
Sorting: "*reas",
|
|
SortingParameters: []string{},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "vendor1",
|
|
ResourceIDs: []string{"RES_GRP1"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor2",
|
|
ResourceIDs: []string{"RES_GRP2"},
|
|
Weight: 0,
|
|
},
|
|
{
|
|
ID: "vendor3",
|
|
FilterIDs: []string{"*gte:~*resources.RES_GRP1.TotalUsage:9"},
|
|
ResourceIDs: []string{"RES_GRP2"},
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_ACNT_1004", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
if !reflect.DeepEqual(expRt4, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt4), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
// ROUTE_ACNT_1005
|
|
expRt5 := &engine.RouteProfile{
|
|
ID: "ROUTE_ACNT_1005",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"*string:~*req.Account:1005"},
|
|
Sorting: "*load",
|
|
SortingParameters: []string{"vendor1:3", "*default:2"},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "vendor1",
|
|
StatIDs: []string{"STATS_VENDOR_1:*sum#1"},
|
|
},
|
|
{
|
|
ID: "vendor2",
|
|
StatIDs: []string{"STATS_VENDOR_2:*sum#1"},
|
|
Weight: 10,
|
|
},
|
|
{
|
|
ID: "vendor3",
|
|
StatIDs: []string{"STATS_VENDOR_2:*distinct#~*req.Usage"},
|
|
},
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_ACNT_1005", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
sort.Strings(reply.SortingParameters)
|
|
sort.Strings(expRt5.SortingParameters)
|
|
if !reflect.DeepEqual(expRt5, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt5), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
// ROUTE_STATS1
|
|
expRt6 := &engine.RouteProfile{
|
|
ID: "ROUTE_HC1",
|
|
Tenant: "cgrates.org",
|
|
FilterIDs: []string{"Fltr_tcc"},
|
|
Sorting: "*hc",
|
|
SortingParameters: []string{},
|
|
Routes: []*engine.Route{
|
|
{
|
|
ID: "route1",
|
|
FilterIDs: []string{"*gte:~*resources.RES_GRP2.Available:6"},
|
|
RatingPlanIDs: []string{"RP_VENDOR2"},
|
|
ResourceIDs: []string{"RES_GRP2"},
|
|
Weight: 20,
|
|
},
|
|
{
|
|
ID: "route2",
|
|
FilterIDs: []string{"*gte:~*resources.RES_GRP1.TotalUsage:9"},
|
|
RatingPlanIDs: []string{"RP_VENDOR1"},
|
|
ResourceIDs: []string{"RES_GRP1"},
|
|
Weight: 20,
|
|
},
|
|
{
|
|
ID: "route3",
|
|
RatingPlanIDs: []string{"RP_VENDOR1"},
|
|
ResourceIDs: []string{"RES_GRP2"},
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1GetRouteProfile,
|
|
&utils.TenantID{ID: "ROUTE_HC1", Tenant: "cgrates.org"},
|
|
&reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Slice(reply.Routes, func(i, j int) bool {
|
|
return reply.Routes[i].ID < reply.Routes[j].ID
|
|
})
|
|
if !reflect.DeepEqual(expRt6, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRt6), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesWeightAccountValue(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "WEIGHT_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1001",
|
|
Sorting: "*weight",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 35.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesWeightAllRoutes(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "WEIGHT_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
utils.Destination: "1003",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1001",
|
|
Sorting: "*weight",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 40.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 35.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesWeightNotMatchingValue(t *testing.T) {
|
|
//change account 1001 balance for not matching vendor2
|
|
attrBal := &utils.AttrSetBalance{
|
|
Tenant: "cgrates.org",
|
|
Account: "1001",
|
|
BalanceType: utils.MetaMonetary,
|
|
Value: 5,
|
|
Balance: map[string]any{
|
|
utils.ID: utils.MetaDefault,
|
|
},
|
|
}
|
|
var result string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.APIerSv1SetBalance, attrBal,
|
|
&result); err != nil {
|
|
t.Error(err)
|
|
} else if result != utils.OK {
|
|
t.Errorf("Unexpected result returned")
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
ID: "WEIGHT_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
utils.Destination: "1003",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1001",
|
|
Sorting: "*weight",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 40.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 35.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCost(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.Usage: "2m30s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1002",
|
|
Sorting: "*lc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.2505,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
//gonna match one route because the totalUsage by ne-allocated resources is 0
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCostDefaultUsage(t *testing.T) {
|
|
// default usage given by routes is 1m
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1002",
|
|
Sorting: "*lc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.0498,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1002,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.6,
|
|
utils.RatingPlanID: "RP_STANDARD",
|
|
utils.Weight: 30.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
//gonna match one route because the totalUsage by ne-allocated resources is 0
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLCSetStatsAndResForMatching(t *testing.T) {
|
|
//not gonna match our vendor1 filter because 6 > 5
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 6,
|
|
},
|
|
}
|
|
var reply string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if reply != "RES_GRP1" {
|
|
t.Errorf("Unexpected reply returned: %s", reply)
|
|
}
|
|
|
|
//gonna match one stats for matching vendor 2 acd filter
|
|
var result []string
|
|
expected := []string{"STATS_VENDOR_2", "STATS_TCC1"}
|
|
ev1 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Category: "vendor2",
|
|
utils.Usage: "2m30s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 1.0,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Strings(result)
|
|
sort.Strings(expected)
|
|
if !reflect.DeepEqual(result, expected) {
|
|
t.Errorf("Expecting: %+v, received: %+v", expected, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCostStats(t *testing.T) {
|
|
//not gonna match vendor1 because of its TotalUsage by allocating resources
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "2m30s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1002",
|
|
Sorting: "*lc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 1.5,
|
|
utils.RatingPlanID: "RP_STANDARD",
|
|
utils.Weight: 30.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
//gonna match one route because the totalUsage by ne-allocated resources is 0
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCosMatchingAllRoutes(t *testing.T) {
|
|
// deallocate resources for matching vendor1
|
|
evRes := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 4,
|
|
},
|
|
}
|
|
var result string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
evRes, &result); err != nil {
|
|
t.Error(err)
|
|
} else if result != "RES_GRP1" {
|
|
t.Errorf("Unexpected result returned: %s", result)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "2m30s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1002",
|
|
Sorting: "*lc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.2505,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor4",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 1.5,
|
|
utils.RatingPlanID: "RP_STANDARD",
|
|
utils.Weight: 30.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCosMaxCost(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "2m30s",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsRoutesMaxCost: 0.35,
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1002",
|
|
Sorting: "*lc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.1245,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.2505,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expSrtdRoutes, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesLowestCosMaxCostNotMatch(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1002",
|
|
utils.Destination: "1003",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "2m30s",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsRoutesMaxCost: 0.05,
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
|
t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesProcessMetrics(t *testing.T) {
|
|
//we will process this stats 2 times
|
|
//Vendor2
|
|
expected := []string{"STATS_TCC1", "STATS_VENDOR_2"}
|
|
ev1 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Category: "vendor2",
|
|
utils.Usage: "2m30s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 1.0,
|
|
},
|
|
}
|
|
var result []string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Strings(expected)
|
|
sort.Strings(result)
|
|
if !reflect.DeepEqual(result, expected) {
|
|
t.Errorf("Expecting: %+v, received: %+v", expected, result)
|
|
}
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Strings(expected)
|
|
sort.Strings(result)
|
|
if !reflect.DeepEqual(result, expected) {
|
|
t.Errorf("Expecting: %+v, received: %+v", expected, result)
|
|
}
|
|
}
|
|
|
|
//Vendor1
|
|
expected = []string{"STATS_TCC1", "STATS_VENDOR_1"}
|
|
ev1 = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Category: "vendor1",
|
|
utils.Usage: "2m30s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 1.0,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Strings(expected)
|
|
sort.Strings(result)
|
|
if !reflect.DeepEqual(result, expected) {
|
|
t.Errorf("Expecting: %+v, received: %+v", expected, result)
|
|
}
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
sort.Strings(expected)
|
|
sort.Strings(result)
|
|
if !reflect.DeepEqual(result, expected) {
|
|
t.Errorf("Expecting: %+v, received: %+v", expected, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesQOS(t *testing.T) {
|
|
//not gonna match vendor3 because *tcc is not bigger that 6
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1003",
|
|
utils.Destination: "1007",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "50s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1003",
|
|
Sorting: "*qos",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.MetaACC: 1.,
|
|
utils.MetaACD: 150. * 1e9,
|
|
"*sum#1": 3.,
|
|
"*distinct#~*req.Usage": 1.,
|
|
utils.MetaTCC: 3.,
|
|
utils.MetaTCD: 450. * 1e9,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.MetaACC: 1.,
|
|
utils.MetaACD: 150. * 1e9,
|
|
"*sum#1": 2.,
|
|
utils.MetaTCC: 2.,
|
|
utils.MetaTCD: 300. * 1e9,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesQOSAllRoutes(t *testing.T) {
|
|
// process *tcc metric for matching vendor3
|
|
ev1 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Category: "vendor1",
|
|
utils.Usage: "2m30s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 10.0,
|
|
},
|
|
}
|
|
var result []string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// match all 3 routes
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1003",
|
|
utils.Destination: "1007",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "50s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1003",
|
|
Sorting: "*qos",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.MetaACC: 4.,
|
|
utils.MetaACD: 150. * 1e9,
|
|
"*sum#1": 3.,
|
|
utils.MetaTCC: 12.,
|
|
utils.MetaTCD: 450. * 1e9,
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.MetaACC: 4.,
|
|
utils.MetaACD: 150. * 1e9,
|
|
"*sum#1": 3.,
|
|
utils.MetaTCC: 12.,
|
|
utils.MetaTCD: 450. * 1e9,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.MetaACC: 1.,
|
|
utils.MetaACD: 150. * 1e9,
|
|
"*sum#1": 3.,
|
|
"*distinct#~*req.Usage": 1.,
|
|
utils.MetaTCC: 3.,
|
|
utils.MetaTCD: 450. * 1e9,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesQOSNotFound(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1008",
|
|
utils.Destination: "1007",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Usage: "50s",
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
|
t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesAllocateResources(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 6,
|
|
},
|
|
}
|
|
var reply string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if reply != "RES_GRP1" {
|
|
t.Errorf("Unexpected reply returned: %s", reply)
|
|
}
|
|
|
|
ev = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1004",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31",
|
|
utils.OptsResourcesUnits: 7,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if reply != "RES_GRP2" {
|
|
t.Errorf("Unexpected reply returned: %s", reply)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesReasNotAllRoutes(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Destination: "1007",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1004",
|
|
Sorting: "*reas",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.ResourceUsage: 6.0,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.ResourceUsage: 7.0,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortingRoutesReasAllRoutes(t *testing.T) {
|
|
evRs := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 9,
|
|
},
|
|
}
|
|
var replyStr string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
evRs, &replyStr); err != nil {
|
|
t.Error(err)
|
|
} else if replyStr != "RES_GRP1" {
|
|
t.Errorf("Unexpected reply returned: %s", replyStr)
|
|
}
|
|
//allocate more resources for matching
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1004",
|
|
utils.Destination: "1007",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1004",
|
|
Sorting: "*reas",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.ResourceUsage: 7.0,
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.ResourceUsage: 7.0,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.ResourceUsage: 9.0,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesRoutesProcessStatsForLoadRtsSorting(t *testing.T) {
|
|
// "STATS_VENDOR_1"
|
|
var reply []string
|
|
expected := []string{"STATS_VENDOR_1", "STATS_TCC1"}
|
|
ev1 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
//utils.AccountField: "1004",
|
|
utils.Category: "vendor1",
|
|
utils.Usage: "1m20s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 1.8,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if err := rtsCaseSv1Rpc.Call(context.Background(), 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 = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
//utils.AccountField: "1004",
|
|
utils.Category: "vendor1",
|
|
utils.Usage: "20s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 1.8,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.StatSv1ProcessEvent, ev1, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if err := rtsCaseSv1Rpc.Call(context.Background(), 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 = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "event1",
|
|
Event: map[string]any{
|
|
//utils.AccountField: "1004",
|
|
utils.Category: "vendor2",
|
|
utils.Usage: "30s",
|
|
utils.AnswerTime: "2013-06-01T05:00:00Z",
|
|
utils.Cost: 0.77,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), 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 := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1005",
|
|
//utils.Destination: "1007",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_ACNT_1005",
|
|
Sorting: "*load",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "vendor3",
|
|
SortingData: map[string]any{
|
|
utils.Load: 2.,
|
|
utils.Ratio: 2.,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor2",
|
|
SortingData: map[string]any{
|
|
utils.Load: 4.,
|
|
utils.Ratio: 2.,
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "vendor1",
|
|
SortingData: map[string]any{
|
|
utils.Load: 7.,
|
|
utils.Ratio: 3.,
|
|
utils.Weight: 0.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), 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 := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
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]any{
|
|
utils.Cost: 0.34235,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.ResourceUsage: 9.,
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "route3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.34235,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.ResourceUsage: 7.,
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortRoutesHigherCostAllocateRes(t *testing.T) {
|
|
// to match route 1, RES_GRP2 must have *gte available 6 resources
|
|
// first we have to remove them
|
|
var result string
|
|
evRs := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1004",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31",
|
|
utils.OptsResourcesUnits: 7,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1ReleaseResources,
|
|
evRs, &result); err != nil {
|
|
t.Error(err)
|
|
} else if result != utils.OK {
|
|
t.Errorf("Unexpected result returned: %s", result)
|
|
}
|
|
|
|
evRs = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 7,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1ReleaseResources,
|
|
evRs, &result); err != nil {
|
|
t.Error(err)
|
|
} else if result != utils.OK {
|
|
t.Errorf("Unexpected result returned: %s", result)
|
|
}
|
|
|
|
evRs = &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1004",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e31",
|
|
utils.OptsResourcesUnits: 1,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), 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.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 4,
|
|
},
|
|
}
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
evRs, &result); err != nil {
|
|
t.Error(err)
|
|
} else if result != "RES_GRP1" {
|
|
t.Errorf("Unexpected result returned: %s", result)
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortRoutesHigherCostV1V3(t *testing.T) {
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1008",
|
|
utils.Destination: "1007",
|
|
utils.SetupTime: "2013-06-01T00:00:00Z",
|
|
utils.Usage: "3m25s",
|
|
},
|
|
}
|
|
expSrtdRoutes := &engine.SortedRoutesList{
|
|
{
|
|
ProfileID: "ROUTE_HC1",
|
|
Sorting: "*hc",
|
|
Routes: []*engine.SortedRoute{
|
|
{
|
|
RouteID: "route3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.34235,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.ResourceUsage: 1.,
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "route1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.17015,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.ResourceUsage: 1.,
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.RouteSv1GetRoutes,
|
|
ev, &reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, expSrtdRoutes) {
|
|
t.Errorf("Expecting: %+v \n, received: %+v", utils.ToJSON(expSrtdRoutes), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func testV1RtsCasesSortRoutesHigherCostAllRoutes(t *testing.T) {
|
|
//allocate for matching all routes
|
|
evRs := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: utils.UUIDSha1Prefix(),
|
|
Event: map[string]any{
|
|
"Account": "1002"},
|
|
APIOpts: map[string]any{
|
|
utils.OptsResourcesUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
|
utils.OptsResourcesUnits: 9,
|
|
},
|
|
}
|
|
var result string
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), utils.ResourceSv1AllocateResources,
|
|
evRs, &result); err != nil {
|
|
t.Error(err)
|
|
} else if result != "RES_GRP1" {
|
|
t.Errorf("Unexpected result returned: %s", result)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
ID: "LC_SORT",
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
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]any{
|
|
utils.Cost: 0.34235,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.ResourceUsage: 9.,
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "route3",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.34235,
|
|
utils.RatingPlanID: "RP_VENDOR1",
|
|
utils.ResourceUsage: 1.,
|
|
utils.Weight: 10.,
|
|
},
|
|
},
|
|
{
|
|
RouteID: "route1",
|
|
SortingData: map[string]any{
|
|
utils.Cost: 0.17015,
|
|
utils.RatingPlanID: "RP_VENDOR2",
|
|
utils.ResourceUsage: 1.,
|
|
utils.Weight: 20.,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
var reply *engine.SortedRoutesList
|
|
if err := rtsCaseSv1Rpc.Call(context.Background(), 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)
|
|
}
|
|
}
|