/* 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package engine import ( "log" "reflect" "sort" "strings" "testing" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) func TestLoaderCSV(t *testing.T) { /* NOTE: Destinations have not been ported. Keep this just in case. DestinationsCSVContent := ` #Tag,Prefix GERMANY,49 GERMANY_O2,41 GERMANY_PREMIUM,43 ALL,49 ALL,41 ALL,43 NAT,0256 NAT,0257 NAT,0723 NAT,+49 RET,0723 RET,0724 SPEC,0723045 PSTN_71,+4971 PSTN_72,+4972 PSTN_70,+4970 DST_UK_Mobile_BIG5,447956 URG,112 EU_LANDLINE,444 EXOTIC,999 ` */ /* TODO: add a test for loading Actions ActionsCSVContent := ` MINI,*topup_reset,,,,*monetary,,,,,*unlimited,,10,10,false,false,10 MINI,*topup,,,,*voice,,NAT,test,,*unlimited,,100s,10,false,false,10 SHARED,*topup,,,,*monetary,,,,SG1,*unlimited,,100,10,false,false,10 TOPUP10_AC,*topup_reset,,,,*monetary,,*any,,,*unlimited,,1,10,false,false,10 TOPUP10_AC1,*topup_reset,,,,*voice,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40s,10,false,false,10 SE0,*topup_reset,,,,*monetary,,,,SG2,*unlimited,,0,10,false,false,10 SE10,*topup_reset,,,,*monetary,,,,SG2,*unlimited,,10,5,false,false,10 SE10,*topup,,,,*monetary,,,,,*unlimited,,10,10,false,false,10 EE0,*topup_reset,,,,*monetary,,,,SG3,*unlimited,,0,10,false,false,10 EE0,*allow_negative,,,,*monetary,,,,,*unlimited,,0,10,false,false,10 DEFEE,*cdrlog,"{""Category"":""^ddi"",""MediationRunId"":""^did_run""}",,,,,,,,,,,,false,false,10 NEG,*allow_negative,,,,*monetary,,,,,*unlimited,,0,10,false,false,10 BLOCK,*topup,,,bblocker,*monetary,,NAT,,,*unlimited,,1,20,true,false,20 BLOCK,*topup,,,bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 BLOCK_EMPTY,*topup,,,bblocker,*monetary,,NAT,,,*unlimited,,0,20,true,false,20 BLOCK_EMPTY,*topup,,,bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 FILTER,*topup,,"{""*and"":[{""Value"":{""*lt"":0}},{""Id"":{""*eq"":""*default""}}]}",bfree,*monetary,,,,,*unlimited,,20,10,false,false,10 EXP,*topup,,,,*voice,,,,,*monthly,*any,300s,10,false,false,10 NOEXP,*topup,,,,*voice,,,,,*unlimited,*any,50s,10,false,false,10 VF,*debit,,,,*monetary,,,,,*unlimited,*any,"{""Method"":""*incremental"",""Params"":{""Units"":10, ""Interval"":""month"", ""Increment"":""day""}}",10,false,false,10 TOPUP_RST_GNR_1000,*topup_reset,"{""*voice"": 60.0,""*data"":1024.0,""*sms"":1.0}",,,*generic,,*any,,,*unlimited,,1000,20,false,false,10 ` */ ResourcesCSVContent := ` #Tenant[0],Id[1],FilterIDs[2],Weights[3],TTL[4],Limit[5],AllocationMessage[6],Blocker[7],Stored[8],Thresholds[9] cgrates.org,ResGroup21,*string:~*req.Account:1001,;10,1s,2,call,true,true, cgrates.org,ResGroup22,*string:~*req.Account:dan,;10,3600s,2,premium_call,true,true, ` IPCSVContent := ` #Tenant[0],ID[1],FilterIDs[2],Weights[3],TTL[4],Stored[5],PoolID[6],PoolFilterIDs[7],PoolType[8],PoolRange[9],PoolStrategy[10],PoolMessage[11],PoolWeights[12],PoolBlockers[13] cgrates.org,IPs1,*string:~*req.Account:1001,;10,1s,true,,,,,,,, cgrates.org,IPs1,,,,,POOL1,*string:~*req.Destination:2001,*ipv4,172.16.1.1/32,*ascending,alloc_success,;15, cgrates.org,IPs1,,,,,POOL1,,,,,,*exists:~*req.NeedMoreWeight:;50,*exists:~*req.ShouldBlock:;true cgrates.org,IPs1,,,,,POOL2,*string:~*req.Destination:2002,*ipv4,192.168.122.1/32,*random,alloc_new,;25,;true cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Destination:3001,*ipv4,127.0.0.1/32,*descending,alloc_msg,;35,;true ` StatsCSVContent := ` #Tenant[0],Id[1],FilterIDs[2],Weights[3],Blockers[4],QueueLength[5],TTL[6],MinItems[7],Stored[8],ThresholdIDs[9],Metrics[10],MetricFilterIDs[11],MetricBlockers[12] cgrates.org,TestStats,*string:~*req.Account:1001,;20,;true,100,1s,2,true,Th1;Th2,*sum#~*req.Value;*average#~*req.Value,, cgrates.org,TestStats,,;20,;true,,,2,true,,*sum#~*req.Usage,, cgrates.org,TestStats2,FLTR_1,;20,;true,100,1s,2,true,Th,*sum#~*req.Value;*sum#~*req.Usage;*average#~*req.Value;*average#~*req.Usage,, cgrates.org,TestStats2,,;20,;true,,,2,true,,*sum#~*req.Cost;*average#~*req.Cost,, ` RankingsCSVContent := ` #Tenant[0],Id[1],QueryInterval[2],StatIDs[2],MetricIDs[3],Sorting[4],SortingParameters[5],ThresholdIDs[6] cgrates.org,Ranking1,15m,Stats2;Stats3;Stats4,Metric1;Metric3,*asc,,THD1;THD2 ` TrendsCSVContent := ` #Tenant[0],Id[1],QueryInterval[2],StatID[3],QueueLength[4],TTL[5],PurgeFilterIDs[6],Trend[7],ThresholdIDs[7] cgrates.org,TREND1,5m,Stats2,-1,-1,,*average,TD1;THD2 ` ThresholdsCSVContent := ` #Tenant[0],Id[1],FilterIDs[2],Weights[3],MaxHits[4],MinHits[5],MinSleep[6],Blocker[7],ActionProfileIDs[8],Async[9],EeIDs[10] cgrates.org,Threshold1,*string:~*req.Account:1001;*string:~*req.RunID:*default,;10,12,10,1s,true,THRESH1,true, ` FiltersCSVContent := ` #Tenant[0],ID[1],Type[2],Element[3],Values[4] cgrates.org,FLTR_1,*string,~*req.Account,1001;1002 cgrates.org,FLTR_1,*prefix,~*req.Destination,10;20 cgrates.org,FLTR_1,*rsr,~*req.Subject,~^1.*1$ cgrates.org,FLTR_1,*rsr,~*req.Destination,1002 cgrates.org,FLTR_ACNT_dan,*string,~*req.Account,dan cgrates.org,FLTR_DST_DE,*destinations,~*req.Destination,DST_DE cgrates.org,FLTR_DST_NL,*destinations,~*req.Destination,DST_NL ` RoutesCSVContent := ` #Tenant[0],ID[1],FilterIDs[2],Weights[3],Blockers[4],Sorting[5],SortingParameters[6],RouteID[7],RouteFilterIDs[8],RouteAccountIDs[9],RouteRateProfileIDs[10],RouteResourceIDs[11],RouteStatIDs[12],RouteWeights[13],RouteBlockers[14],RouteParameters[15] cgrates.org,RoutePrf1,*string:~*req.Account:dan,;20,,*lc,,route1,FLTR_ACNT_dan,Account1;Account1_1,RPL_1,ResGroup1,Stat1,;10,;true,param1 cgrates.org,RoutePrf1,,,,,,route1,,,RPL_2,ResGroup2,,;10,, cgrates.org,RoutePrf1,,,,,,route1,FLTR_DST_DE,Account2,RPL_3,ResGroup3,Stat2,;10,, cgrates.org,RoutePrf1,,,,,,route1,,,,ResGroup4,Stat3,;10,, ` AttributesCSVContent := ` #Tenant,ID,FilterIDs,Weights,Blockers,AttributeFilterIDs,AttributeBlockers,Path,Type,Value cgrates.org,ALS1,*string:~*req.Account:1001;*string:~*opts.*context:con1,;20,;true,*string:~*req.Field1:Initial,;true,*req.Field1,*variable,Sub1 cgrates.org,ALS1,*string:~*opts.*context:con2|con3,,,,*string:~*req.Account:1002;true,*req.Field2,*variable,Sub2 ` ChargersCSVContent := ` #Tenant,ID,FilterIDs,Weights,Blockers,RunID,AttributeIDs cgrates.org,Charger1,*string:~*req.Account:1001,;20,,*rated,ATTR_1001_SIMPLEAUTH ` DispatcherCSVContent := ` #Tenant,ID,FilterIDs,Weight,Strategy,StrategyParameters,ConnID,ConnFilterIDs,ConnWeight,ConnBlocker,ConnParameters cgrates.org,D1,*string:~*req.Account:1001,20,*first,,C1,*gt:~*req.Usage:10,10,false,192.168.56.203 cgrates.org,D1,,,*first,,C2,*lt:~*req.Usage:10,10,false,192.168.56.204 ` DispatcherHostCSVContent := ` #Tenant[0],ID[1],Address[2],Transport[3],ConnectAttempts[4],Reconnects[5],MaxReconnectInterval[6],ConnectTimeout[7],ReplyTimeout[8],Tls[9],ClientKey[10],ClientCertificate[11],CaCertificate[12] cgrates.org,ALL,127.0.0.1:6012,*json,1,3,5m,1m,2m,false,,, ` RateProfileCSVContent := ` #Tenant,ID,FilterIDs,Weights,MinCost,MaxCost,MaxCostStrategy,RateID,RateFilterIDs,RateActivationStart,RateWeights,RateBlocker,RateIntervalStart,RateFixedFee,RateRecurrentFee,RateUnit,RateIncrement cgrates.org,RP1,*string:~*req.Subject:1001,;0,0.1,0.6,*free,RT_WEEK,,"* * * * 1-5",;0,false,0s,0,0.12,1m,1m cgrates.org,RP1,,,,,,RT_WEEK,,,,,1m,1.234,0.06,1m,1s cgrates.org,RP1,,,,,,RT_WEEKEND,,"* * * * 0,6",;10,false,0s,0.089,0.06,1m,1s cgrates.org,RP1,,,,,,RT_CHRISTMAS,,* * 24 12 *,;30,false,0s,0.0564,0.06,1m,1s ` ActionProfileCSVContent := ` #Tenant,ID,FilterIDs,Weights,Blockers,Schedule,TargetType,TargetIDs,ActionID,ActionFilterIDs,ActionTTL,ActionType,ActionOpts,ActionWeights,ActionBlockers,ActionDiktatsID,ActionDiktatsFilterIDs,ActionDiktatsOpts,ActionDiktatsWeights,ActionDiktatsBlockers cgrates.org,ONE_TIME_ACT,,;10,,*asap,*accounts,1001;1002,TOPUP,,0s,*add_balance,,,,ADDBALVALUE,,*balancePath:*balance.TestBalance.Value;*balanceValue:10,, cgrates.org,ONE_TIME_ACT,,,,,,,SET_BALANCE_TEST_DATA,,0s,*set_balance,,,,SETBALTYPE,,*balancePath:*balance.TestDataBalance.Type;*balanceValue:*data,, cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_DATA,,0s,*add_balance,,,,ADDBALVALUE,,*balancePath:*balance.TestDataBalance.Value;*balanceValue:1024,, cgrates.org,ONE_TIME_ACT,,,,,,,SET_BALANCE_TEST_VOICE,,0s,*set_balance,,,,SETBALTYPE,,*balancePath:*balance.TestVoiceBalance.Type;*balanceValue:*voice,, cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_VOICE,,0s,*add_balance,,,,ADDBALVALUE1,,*balancePath:*balance.TestVoiceBalance.Value;*balanceValue:15m15s,, cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_VOICE,,0s,*add_balance,,,,ADDBALVALUE2,,*balancePath:*balance.TestVoiceBalance2.Value;*balanceValue:15m15s,, ` AccountCSVContent := ` #Tenant,ID,FilterIDs,Weights,Blockers,Opts,BalanceID,BalanceFilterIDs,BalanceWeights,BalanceBlockers,BalanceType,BalanceUnits,BalanceUnitFactors,BalanceOpts,BalanceCostIncrements,BalanceAttributeIDs,BalanceRateProfileIDs,ThresholdIDs cgrates.org,1001,,;20,,,MonetaryBalance,,;10,,*monetary,14,fltr1&fltr2;100;fltr3;200,,fltr1&fltr2;1.3;2.3;3.3,attr1;attr2,,*none cgrates.org,1001,,,,,VoiceBalance,,;10,*string:~*req.Destination:1002;true;;false,*voice,1h,,,,,, ` testTPID := "LoaderCSVTests" idb, err := NewInternalDB(nil, nil, nil, config.CgrConfig().DbCfg().Items) if err != nil { t.Fatal(err) } dbCM := NewDBConnManager(map[string]DataDB{utils.MetaDefault: idb}, config.CgrConfig().DbCfg()) csvr, err := NewTpReader(dbCM, NewStringCSVStorage(utils.CSVSep, ResourcesCSVContent, IPCSVContent, StatsCSVContent, RankingsCSVContent, TrendsCSVContent, ThresholdsCSVContent, FiltersCSVContent, RoutesCSVContent, AttributesCSVContent, ChargersCSVContent, DispatcherCSVContent, DispatcherHostCSVContent, RateProfileCSVContent, ActionProfileCSVContent, AccountCSVContent), testTPID, "", nil, nil) if err != nil { log.Print("error when creating TpReader:", err) } if err := csvr.LoadFilters(); err != nil { log.Print("error in LoadFilter:", err) } if err := csvr.LoadResourceProfiles(); err != nil { log.Print("error in LoadResourceProfiles:", err) } if err := csvr.LoadIPs(); err != nil { log.Print("error in LoadIPProfiles:") } if err := csvr.LoadStats(); err != nil { log.Print("error in LoadStats:", err) } if err := csvr.LoadThresholds(); err != nil { log.Print("error in LoadThresholds:", err) } if err := csvr.LoadRouteProfiles(); err != nil { log.Print("error in LoadRouteProfiles:", err) } if err := csvr.LoadAttributeProfiles(); err != nil { log.Print("error in LoadAttributeProfiles:", err) } if err := csvr.LoadChargerProfiles(); err != nil { log.Print("error in LoadChargerProfiles:", err) } if err := csvr.LoadRateProfiles(); err != nil { log.Print("error in LoadRateProfiles:", err) } if err := csvr.LoadActionProfiles(); err != nil { log.Print("error in LoadActionProfiles: ", err) } if err := csvr.LoadAccounts(); err != nil { log.Print("error in LoadActionProfiles: ", err) } if err := csvr.WriteToDatabase(false, false); err != nil { log.Print("error when writing into database ", err) } t.Run("load ResourceProfiles", func(t *testing.T) { eResProfiles := map[utils.TenantID]*utils.TPResourceProfile{ {Tenant: "cgrates.org", ID: "ResGroup21"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "ResGroup21", FilterIDs: []string{"*string:~*req.Account:1001"}, UsageTTL: "1s", AllocationMessage: "call", Weights: ";10", Limit: "2", Blocker: true, Stored: true, }, {Tenant: "cgrates.org", ID: "ResGroup22"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "ResGroup22", FilterIDs: []string{"*string:~*req.Account:dan"}, UsageTTL: "3600s", AllocationMessage: "premium_call", Blocker: true, Stored: true, Weights: ";10", Limit: "2", }, } resKey := utils.TenantID{Tenant: "cgrates.org", ID: "ResGroup21"} if len(csvr.resProfiles) != len(eResProfiles) { t.Errorf("Failed to load ResourceProfiles: %s", utils.ToIJSON(csvr.resProfiles)) } else if !reflect.DeepEqual(eResProfiles[resKey], csvr.resProfiles[resKey]) { t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eResProfiles[resKey]), utils.ToJSON(csvr.resProfiles[resKey])) } }) t.Run("load IPProfiles", func(t *testing.T) { eIPsProfiles := map[utils.TenantID]*utils.TPIPProfile{ {Tenant: "cgrates.org", ID: "IPs1"}: { TPid: "LoaderCSVTests", Tenant: "cgrates.org", ID: "IPs1", FilterIDs: []string{"*string:~*req.Account:1001"}, Weights: ";10", TTL: "1s", Stored: true, Pools: []*utils.TPIPPool{ { ID: "POOL1", FilterIDs: []string{"*string:~*req.Destination:2001"}, Type: "*ipv4", Range: "172.16.1.1/32", Strategy: "*ascending", Message: "alloc_success", Weights: ";15", Blockers: "", }, { ID: "POOL1", FilterIDs: nil, Type: "", Range: "", Strategy: "", Message: "", Weights: "*exists:~*req.NeedMoreWeight:;50", Blockers: "*exists:~*req.ShouldBlock:;true", }, { ID: "POOL2", FilterIDs: []string{"*string:~*req.Destination:2002"}, Type: "*ipv4", Range: "192.168.122.1/32", Strategy: "*random", Message: "alloc_new", Weights: ";25", Blockers: ";true", }, }, }, {Tenant: "cgrates.org", ID: "IPs2"}: { TPid: "LoaderCSVTests", Tenant: "cgrates.org", ID: "IPs2", FilterIDs: []string{"*string:~*req.Account:1002"}, Weights: ";20", TTL: "2s", Stored: false, Pools: []*utils.TPIPPool{ { ID: "POOL1", FilterIDs: []string{"*string:~*req.Destination:3001"}, Type: "*ipv4", Range: "127.0.0.1/32", Strategy: "*descending", Message: "alloc_msg", Weights: ";35", Blockers: ";true", }, }, }} if len(csvr.ipProfiles) != len(eIPsProfiles) { t.Errorf("Failed to load IPProfiles: %s", utils.ToIJSON(csvr.ipProfiles)) } for key, val := range eIPsProfiles { if diff := cmp.Diff(val, csvr.ipProfiles[key], cmpopts.SortSlices(func(a, b *utils.TPIPPool) bool { if a.ID != b.ID { return a.ID < b.ID } return a.Weights < b.Weights })); diff != "" { t.Errorf("IPProfile mismatch (-want +got):\n%s", diff) } } }) t.Run("load StatProfiles", func(t *testing.T) { eStats := map[utils.TenantID]*utils.TPStatProfile{ {Tenant: "cgrates.org", ID: "TestStats"}: { Tenant: "cgrates.org", TPid: testTPID, ID: "TestStats", FilterIDs: []string{"*string:~*req.Account:1001", "*ai:~*req.AnswerTime:2014-07-29T15:00:00Z"}, QueueLength: 100, TTL: "1s", Metrics: []*utils.MetricWithFilters{ { MetricID: "*sum#Value", }, { MetricID: "*sum#Usage", }, { MetricID: "*average#Value", }, }, ThresholdIDs: []string{"Th1", "Th2"}, Blockers: ";true", Stored: true, Weights: ";20", MinItems: 2, }, {Tenant: "cgrates.org", ID: "TestStats2"}: { Tenant: "cgrates.org", TPid: testTPID, ID: "TestStats2", FilterIDs: []string{"FLTR_1", "*ai:~*req.AnswerTime:2014-07-29T15:00:00Z"}, QueueLength: 100, TTL: "1s", Metrics: []*utils.MetricWithFilters{ { MetricID: "*sum#Value", }, { MetricID: "*sum#Usage", }, { FilterIDs: []string{"*string:Account:1001"}, MetricID: "*sum#Cost", }, { MetricID: "*average#Value", }, { MetricID: "*average#Usage", }, { FilterIDs: []string{"*string:Account:1001"}, MetricID: "*average#Cost", }, }, ThresholdIDs: []string{"Th"}, Blockers: ";true", Stored: true, Weights: ";20", MinItems: 2, }, } stKeys := []utils.TenantID{ {Tenant: "cgrates.org", ID: "TestStats"}, {Tenant: "cgrates.org", ID: "TestStats2"}, } for _, stKey := range stKeys { if len(csvr.sqProfiles) != len(eStats) { t.Errorf("Failed to load StatQueueProfiles: %s", utils.ToJSON(csvr.sqProfiles)) } else if !reflect.DeepEqual(eStats[stKey].Tenant, csvr.sqProfiles[stKey].Tenant) { t.Errorf("Expecting: %s, received: %s", eStats[stKey].Tenant, csvr.sqProfiles[stKey].Tenant) } else if !reflect.DeepEqual(eStats[stKey].ID, csvr.sqProfiles[stKey].ID) { t.Errorf("Expecting: %s, received: %s", eStats[stKey].ID, csvr.sqProfiles[stKey].ID) } else if !reflect.DeepEqual(len(eStats[stKey].ThresholdIDs), len(csvr.sqProfiles[stKey].ThresholdIDs)) { t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eStats[stKey].ThresholdIDs), utils.ToJSON(csvr.sqProfiles[stKey].ThresholdIDs)) } else if !reflect.DeepEqual(len(eStats[stKey].Metrics), len(csvr.sqProfiles[stKey].Metrics)) { t.Errorf("Expecting: %s, \n received: %s", utils.ToJSON(eStats[stKey].Metrics), utils.ToJSON(csvr.sqProfiles[stKey].Metrics)) } } }) t.Run("load ThresholdProfiles", func(t *testing.T) { eThresholds := map[utils.TenantID]*utils.TPThresholdProfile{ {Tenant: "cgrates.org", ID: "Threshold1"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "Threshold1", FilterIDs: []string{"*string:~*req.Account:1001", "*string:~*req.RunID:*default"}, MaxHits: 12, MinHits: 10, MinSleep: "1s", Blocker: true, Weights: ";10", ActionProfileIDs: []string{"THRESH1"}, Async: true, }, } eThresholdReverse := map[utils.TenantID]*utils.TPThresholdProfile{ {Tenant: "cgrates.org", ID: "Threshold1"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "Threshold1", FilterIDs: []string{"*string:~*req.RunID:*default", "*string:~*req.Account:1001"}, MaxHits: 12, MinHits: 10, MinSleep: "1s", Blocker: true, Weights: ";10", ActionProfileIDs: []string{"THRESH1"}, Async: true, }, } thkey := utils.TenantID{Tenant: "cgrates.org", ID: "Threshold1"} if len(csvr.thProfiles) != len(eThresholds) { t.Errorf("Failed to load ThresholdProfiles: %s", utils.ToIJSON(csvr.thProfiles)) } else if !reflect.DeepEqual(eThresholds[thkey], csvr.thProfiles[thkey]) && !reflect.DeepEqual(eThresholdReverse[thkey], csvr.thProfiles[thkey]) { t.Errorf("Expecting: %+v , %+v , received: %+v", utils.ToJSON(eThresholds[thkey]), utils.ToJSON(eThresholdReverse[thkey]), utils.ToJSON(csvr.thProfiles[thkey])) } }) t.Run("load FilterProfiles", func(t *testing.T) { eFilters := map[utils.TenantID]*utils.TPFilterProfile{ {Tenant: "cgrates.org", ID: "FLTR_1"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "FLTR_1", Filters: []*utils.TPFilter{ { Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.AccountField, Type: utils.MetaString, Values: []string{"1001", "1002"}, }, { Element: "~*req.Destination", Type: utils.MetaPrefix, Values: []string{"10", "20"}, }, { Element: "~*req.Subject", Type: utils.MetaRSR, Values: []string{"~^1.*1$"}, }, { Element: "~*req.Destination", Type: utils.MetaRSR, Values: []string{"1002"}, }, }, }, {Tenant: "cgrates.org", ID: "FLTR_ACNT_dan"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "FLTR_ACNT_dan", Filters: []*utils.TPFilter{ { Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.AccountField, Type: utils.MetaString, Values: []string{"dan"}, }, }, }, {Tenant: "cgrates.org", ID: "FLTR_DST_DE"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "FLTR_DST_DE", Filters: []*utils.TPFilter{ { Element: "~*req.Destination", Values: []string{"DST_DE"}, }, }, }, {Tenant: "cgrates.org", ID: "FLTR_DST_NL"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "FLTR_DST_NL", Filters: []*utils.TPFilter{ { Element: "~*req.Destination", Values: []string{"DST_NL"}, }, }, }, } fltrKey := utils.TenantID{Tenant: "cgrates.org", ID: "FLTR_1"} if len(csvr.filters) != len(eFilters) { t.Errorf("Failed to load Filters: %s", utils.ToIJSON(csvr.filters)) } else if !reflect.DeepEqual(eFilters[fltrKey], csvr.filters[fltrKey]) { t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eFilters[fltrKey]), utils.ToJSON(csvr.filters[fltrKey])) } }) t.Run("load RouteProfiles", func(t *testing.T) { eSppProfile := &utils.TPRouteProfile{ TPid: testTPID, Tenant: "cgrates.org", ID: "RoutePrf1", FilterIDs: []string{"*string:~*req.Account:dan"}, Sorting: utils.MetaLC, Routes: []*utils.TPRoute{ { ID: "route1", FilterIDs: []string{"FLTR_ACNT_dan"}, AccountIDs: []string{"Account1", "Account1_1"}, RateProfileIDs: []string{"RPL_1"}, ResourceIDs: []string{"ResGroup1"}, StatIDs: []string{"Stat1"}, Weights: ";10", Blockers: ";true", RouteParameters: "param1", }, { ID: "route1", RateProfileIDs: []string{"RPL_2"}, ResourceIDs: []string{"ResGroup2", "ResGroup4"}, StatIDs: []string{"Stat3"}, Weights: ";10", RouteParameters: utils.EmptyString, }, { ID: "route1", FilterIDs: []string{"FLTR_DST_DE"}, AccountIDs: []string{"Account2"}, RateProfileIDs: []string{"RPL_3"}, ResourceIDs: []string{"ResGroup3"}, StatIDs: []string{"Stat2"}, Weights: ";10", RouteParameters: utils.EmptyString, }, }, Weights: ";20", } sort.Slice(eSppProfile.Routes, func(i, j int) bool { return strings.Compare(eSppProfile.Routes[i].ID+strings.Join(eSppProfile.Routes[i].FilterIDs, utils.ConcatenatedKeySep), eSppProfile.Routes[j].ID+strings.Join(eSppProfile.Routes[j].FilterIDs, utils.ConcatenatedKeySep)) < 0 }) resKey := utils.TenantID{Tenant: "cgrates.org", ID: "RoutePrf1"} if len(csvr.routeProfiles) != 1 { t.Errorf("Failed to load RouteProfiles: %s", utils.ToIJSON(csvr.routeProfiles)) } else { rcvRoute := csvr.routeProfiles[resKey] if rcvRoute == nil { t.Fatal("Missing route") } sort.Slice(rcvRoute.Routes, func(i, j int) bool { return strings.Compare(rcvRoute.Routes[i].ID+strings.Join(rcvRoute.Routes[i].FilterIDs, utils.ConcatenatedKeySep), rcvRoute.Routes[j].ID+strings.Join(rcvRoute.Routes[j].FilterIDs, utils.ConcatenatedKeySep)) < 0 }) if !reflect.DeepEqual(eSppProfile, rcvRoute) { t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eSppProfile), utils.ToJSON(rcvRoute)) } } }) t.Run("load AttributeProfiles", func(t *testing.T) { eAttrProfiles := map[utils.TenantID]*utils.TPAttributeProfile{ {Tenant: "cgrates.org", ID: "ALS1"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "ALS1", FilterIDs: []string{"*string:~*opts.*context:con1", "*string:~*opts.*context:con2|con3", "*string:~*req.Account:1001"}, Attributes: []*utils.TPAttribute{ { FilterIDs: []string{"*string:~*req.Field1:Initial"}, Blockers: ";true", Path: utils.MetaReq + utils.NestingSep + "Field1", Type: utils.MetaVariable, Value: "Sub1", }, { FilterIDs: []string{}, Blockers: "*string:~*req.Account:1002;true", Path: utils.MetaReq + utils.NestingSep + "Field2", Type: utils.MetaVariable, Value: "Sub2", }, }, Blockers: ";true", Weights: ";20", }, } resKey := utils.TenantID{Tenant: "cgrates.org", ID: "ALS1"} sort.Strings(csvr.attributeProfiles[resKey].FilterIDs) if len(csvr.attributeProfiles) != len(eAttrProfiles) { t.Errorf("Failed to load attributeProfiles: %s", utils.ToIJSON(csvr.attributeProfiles)) } else if !reflect.DeepEqual(eAttrProfiles[resKey].Tenant, csvr.attributeProfiles[resKey].Tenant) { t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].Tenant, csvr.attributeProfiles[resKey].Tenant) } else if !reflect.DeepEqual(eAttrProfiles[resKey].ID, csvr.attributeProfiles[resKey].ID) { t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].ID, csvr.attributeProfiles[resKey].ID) } else if !reflect.DeepEqual(eAttrProfiles[resKey].FilterIDs, csvr.attributeProfiles[resKey].FilterIDs) { t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].FilterIDs, csvr.attributeProfiles[resKey].FilterIDs) } else if !reflect.DeepEqual(eAttrProfiles[resKey].Attributes, csvr.attributeProfiles[resKey].Attributes) { t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eAttrProfiles[resKey].Attributes), utils.ToJSON(csvr.attributeProfiles[resKey].Attributes)) } else if !reflect.DeepEqual(eAttrProfiles[resKey].Blockers, csvr.attributeProfiles[resKey].Blockers) { t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].Blockers, csvr.attributeProfiles[resKey].Blockers) } }) t.Run("load ChargerProfiles", func(t *testing.T) { eChargerProfiles := map[utils.TenantID]*utils.TPChargerProfile{ {Tenant: "cgrates.org", ID: "Charger1"}: { TPid: testTPID, Tenant: "cgrates.org", ID: "Charger1", FilterIDs: []string{"*string:~*req.Account:1001"}, RunID: "*rated", AttributeIDs: []string{"ATTR_1001_SIMPLEAUTH"}, Weights: ";20", }, } cppKey := utils.TenantID{Tenant: "cgrates.org", ID: "Charger1"} if len(csvr.chargerProfiles) != len(eChargerProfiles) { t.Errorf("Failed to load chargerProfiles: %s", utils.ToIJSON(csvr.chargerProfiles)) } else if !reflect.DeepEqual(eChargerProfiles[cppKey], csvr.chargerProfiles[cppKey]) { t.Errorf("Expecting: %+v, received: %+v", eChargerProfiles[cppKey], csvr.chargerProfiles[cppKey]) } }) t.Run("load RateProfiles", func(t *testing.T) { eRatePrf := &utils.TPRateProfile{ TPid: testTPID, Tenant: "cgrates.org", ID: "RP1", FilterIDs: []string{"*string:~*req.Subject:1001"}, Weights: ";0", MinCost: 0.1, MaxCost: 0.6, MaxCostStrategy: "*free", Rates: map[string]*utils.TPRate{ "RT_WEEK": { ID: "RT_WEEK", Weights: ";0", ActivationTimes: "* * * * 1-5", IntervalRates: []*utils.TPIntervalRate{ { IntervalStart: "0s", RecurrentFee: 0.12, Unit: "1m", Increment: "1m", }, { IntervalStart: "1m", FixedFee: 1.234, RecurrentFee: 0.06, Unit: "1m", Increment: "1s", }, }, }, "RT_WEEKEND": { ID: "RT_WEEKEND", Weights: ";10", ActivationTimes: "* * * * 0,6", IntervalRates: []*utils.TPIntervalRate{ { IntervalStart: "0s", FixedFee: 0.089, RecurrentFee: 0.06, Unit: "1m", Increment: "1s", }, }, }, "RT_CHRISTMAS": { ID: "RT_CHRISTMAS", Weights: ";30", ActivationTimes: "* * 24 12 *", IntervalRates: []*utils.TPIntervalRate{ { IntervalStart: "0s", FixedFee: 0.0564, RecurrentFee: 0.06, Unit: "1m", Increment: "1s", }, }, }, }, } if len(csvr.rateProfiles) != 1 { t.Errorf("Failed to load rateProfiles: %s", utils.ToIJSON(csvr.rateProfiles)) } dppKey := utils.TenantID{Tenant: "cgrates.org", ID: "RP1"} sort.Slice(csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates, func(i, j int) bool { return csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates[i].IntervalStart < csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates[j].IntervalStart }) if !reflect.DeepEqual(eRatePrf, csvr.rateProfiles[dppKey]) { t.Errorf("Expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf), utils.ToJSON(csvr.rateProfiles[dppKey])) } }) t.Run("load ActionProfiles", func(t *testing.T) { expected := &utils.TPActionProfile{ TPid: testTPID, Tenant: "cgrates.org", ID: "ONE_TIME_ACT", Weights: ";10", Schedule: utils.MetaASAP, Targets: []*utils.TPActionTarget{ { TargetType: utils.MetaAccounts, TargetIDs: []string{"1001", "1002"}, }, }, Actions: []*utils.TPAPAction{ { ID: "TOPUP", TTL: "0s", Type: "*add_balance", Diktats: []*utils.TPAPDiktat{{ ID: "ADDBALVALUE", Opts: "*balancePath:*balance.TestBalance.Value;*balanceValue:10", }}, }, { ID: "SET_BALANCE_TEST_DATA", TTL: "0s", Type: "*set_balance", Diktats: []*utils.TPAPDiktat{{ ID: "SETBALTYPE", Opts: "*balancePath:*balance.TestDataBalance.Type;*balanceValue:*data", }}, }, { ID: "TOPUP_TEST_DATA", TTL: "0s", Type: "*add_balance", Diktats: []*utils.TPAPDiktat{{ ID: "ADDBALVALUE", Opts: "*balancePath:*balance.TestDataBalance.Value;*balanceValue:1024", }}, }, { ID: "SET_BALANCE_TEST_VOICE", TTL: "0s", Type: "*set_balance", Diktats: []*utils.TPAPDiktat{{ ID: "SETBALTYPE", Opts: "*balancePath:*balance.TestVoiceBalance.Type;*balanceValue:*voice", }}, }, { ID: "TOPUP_TEST_VOICE", TTL: "0s", Type: "*add_balance", Diktats: []*utils.TPAPDiktat{{ ID: "ADDBALVALUE1", Opts: "*balancePath:*balance.TestVoiceBalance.Value;*balanceValue:15m15s", }, { ID: "ADDBALVALUE2", Opts: "*balancePath:*balance.TestVoiceBalance2.Value;*balanceValue:15m15s", }}, }, }, } if len(csvr.actionProfiles) != 1 { t.Fatalf("Failed to load ActionProfiles: %s", utils.ToJSON(csvr.actionProfiles)) } actPrfKey := utils.TenantID{ Tenant: "cgrates.org", ID: "ONE_TIME_ACT", } sort.Slice(expected.Actions, func(i, j int) bool { return false }) sort.Slice(expected.Targets[0].TargetIDs, func(i, j int) bool { return expected.Targets[0].TargetIDs[i] < expected.Targets[0].TargetIDs[j] }) sort.Slice(csvr.actionProfiles[actPrfKey].Targets[0].TargetIDs, func(i, j int) bool { return csvr.actionProfiles[actPrfKey].Targets[0].TargetIDs[i] < csvr.actionProfiles[actPrfKey].Targets[0].TargetIDs[j] }) if !reflect.DeepEqual(csvr.actionProfiles[actPrfKey], expected) { t.Errorf("Expecting: %+v,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(csvr.actionProfiles[actPrfKey])) } }) t.Run("load Accounts", func(t *testing.T) { expected := &utils.TPAccount{ TPid: testTPID, Tenant: "cgrates.org", ID: "1001", Weights: ";20", Balances: map[string]*utils.TPAccountBalance{ "MonetaryBalance": { ID: "MonetaryBalance", Weights: ";10", Type: utils.MetaMonetary, CostIncrement: []*utils.TPBalanceCostIncrement{ { FilterIDs: []string{"fltr1", "fltr2"}, Increment: "1.3", FixedFee: utils.Float64Pointer(2.3), RecurrentFee: utils.Float64Pointer(3.3), }, }, AttributeIDs: []string{"attr1", "attr2"}, UnitFactors: []*utils.TPBalanceUnitFactor{ { FilterIDs: []string{"fltr1", "fltr2"}, Factor: 100, }, { FilterIDs: []string{"fltr3"}, Factor: 200, }, }, Units: "14", }, "VoiceBalance": { ID: "VoiceBalance", Weights: ";10", Blockers: "*string:~*req.Destination:1002;true;;false", Type: utils.MetaVoice, Units: "1h", }, }, ThresholdIDs: []string{utils.MetaNone}, } if len(csvr.accounts) != 1 { t.Fatalf("Failed to load Accounts: %s", utils.ToJSON(csvr.actionProfiles)) } accPrfKey := utils.TenantID{ Tenant: "cgrates.org", ID: "1001", } sort.Strings(csvr.accounts[accPrfKey].Balances["MonetaryBalance"].AttributeIDs) if !reflect.DeepEqual(csvr.accounts[accPrfKey], expected) { t.Errorf("Expecting: %+v,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(csvr.accounts[accPrfKey])) } }) }