func TestGetCostMaxDebitRoundingIssue(t *testing.T) { ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) for _, at := range ap { at.Execute() } cd := &CallDescriptor{ Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "dy", Account: "dy", Destination: "0723123113", TimeStart: time.Date(2015, 10, 26, 13, 29, 27, 0, time.UTC), TimeEnd: time.Date(2015, 10, 26, 13, 29, 51, 0, time.UTC), MaxCostSoFar: 0, } acc, err := accountingStorage.GetAccount("cgrates.org:dy") if err != nil || acc.BalanceMap[utils.MONETARY][0].Value != 1 { t.Errorf("Error getting account: %+v (%v)", utils.ToIJSON(acc), err) } cc, err := cd.MaxDebit() expected := 0.39 if cc.Cost != expected || err != nil { t.Log(utils.ToIJSON(cc)) t.Errorf("Expected %v was %+v", expected, cc) } acc, err = accountingStorage.GetAccount("cgrates.org:dy") if err != nil || acc.BalanceMap[utils.MONETARY][0].Value != 1-expected { t.Errorf("Error getting account: %+v (%v)", utils.ToIJSON(acc), err) } }
func TestTpZeroNegativeCost(t *testing.T) { if !*testIntegration { return } tStart := time.Date(2016, 3, 31, 0, 0, 0, 0, time.UTC) cd := engine.CallDescriptor{ Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "free", Account: "1013", Destination: "+4915", DurationIndex: 0, TimeStart: tStart, TimeEnd: tStart.Add(time.Duration(20) * time.Second), } var cc engine.CallCost if err := tpRPC.Call("Responder.Debit", cd, &cc); err != nil { t.Error("Got error on Responder.GetCost: ", err.Error()) } else if cc.GetDuration() != 20*time.Second { t.Errorf("Calling Responder.MaxDebit got callcost: %v", utils.ToIJSON(cc)) } var acnt engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1013"} if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error("Got error on ApierV2.GetAccount: ", err.Error()) } else if acnt.BalanceMap[utils.VOICE][0].Value != 100.0 { t.Errorf("Calling ApierV2.GetAccount received: %s", utils.ToIJSON(acnt)) } }
func TestApierResetAccountActionTriggers(t *testing.T) { if !*testIntegration { return } var acnt engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"} if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.ActionTriggers[0].Executed == true { t.Errorf("wrong action trigger executed flag: %s", utils.ToIJSON(acnt.ActionTriggers)) } var reply string if err := tpRPC.Call("ApierV2.ResetAccountActionTriggers", v1.AttrResetAccountActionTriggers{ Tenant: "cgrates.org", Account: "1005", GroupID: "STANDARD_TRIGGERS", Executed: true, }, &reply); err != nil { t.Error("Error on ApierV2.ResetAccountActionTriggers: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV2.ResetAccountActionTriggers got reply: %s", reply) } if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.ActionTriggers[0].Executed == false { t.Errorf("wrong action trigger executed flag: %s", utils.ToIJSON(acnt.ActionTriggers)) } }
func TestDestManagCacheWithGetCache(t *testing.T) { if !*testIntegration { return } if err := engine.InitDataDb(destCfg); err != nil { t.Fatal(err) } var reply string if err := destRPC.Call("ApierV1.ReloadCache", utils.AttrReloadCache{}, &reply); err != nil { t.Error("Got error on ApierV1.ReloadCache: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV1.ReloadCache received: %+v", reply) } attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "cacheall"), FlushDb: true} if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil { t.Error(err) } else if destLoadInst.RatingLoadID == "" || destLoadInst.AccountingLoadID == "" { t.Error("Empty loadId received, loadInstance: ", destLoadInst) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups dests := make([]*engine.Destination, 0) if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil { t.Error("Got error on ApierV2.GetDestinations: ", err.Error()) } else if len(dests) != 1 { t.Errorf("Calling ApierV2.GetDestinations got reply: %v", utils.ToIJSON(dests)) } var rcvStats utils.CacheStats if err := destRPC.Call("ApierV1.GetCacheStats", utils.AttrCacheStats{}, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) } else if rcvStats.Destinations != 2 { t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats) } attrs = &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "cacheone"), FlushDb: true} if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil { t.Error(err) } else if destLoadInst.RatingLoadID == "" || destLoadInst.AccountingLoadID == "" { t.Error("Empty loadId received, loadInstance: ", destLoadInst) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups dests = make([]*engine.Destination, 0) if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil { t.Error("Got error on ApierV2.GetDestinations: ", err.Error()) } else if len(dests) != 1 { t.Errorf("Calling ApierV2.GetDestinations got reply: %v", utils.ToIJSON(dests)) } if err := destRPC.Call("ApierV1.GetCacheStats", utils.AttrCacheStats{}, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) } else if rcvStats.Destinations != 1 { t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats) } }
func TestRatingProfileYearMonthDay(t *testing.T) { ri := &RatingInfo{ RateIntervals: RateIntervalList{ &RateInterval{ Timing: &RITiming{ StartTime: "09:00:00", }, }, &RateInterval{ Timing: &RITiming{ StartTime: "00:00:00", }, }, &RateInterval{ Timing: &RITiming{ Years: utils.Years{2016}, Months: utils.Months{1}, MonthDays: utils.MonthDays{6, 7}, WeekDays: utils.WeekDays{}, StartTime: "19:00:00", }, }, }, } ts := &TimeSpan{ TimeStart: time.Date(2016, 1, 6, 23, 40, 0, 0, time.UTC), TimeEnd: time.Date(2016, 1, 7, 1, 1, 30, 0, time.UTC), } rIntervals := ri.SelectRatingIntevalsForTimespan(ts) if len(rIntervals) != 1 || rIntervals[0].Timing.StartTime != "19:00:00" { t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals)) } }
func TestRatingProfileRIforTSMidnight(t *testing.T) { ri := &RatingInfo{ RateIntervals: RateIntervalList{ &RateInterval{ Timing: &RITiming{ StartTime: "09:00:00", }, }, &RateInterval{ Timing: &RITiming{ StartTime: "00:00:00", }, }, &RateInterval{ Timing: &RITiming{ StartTime: "19:00:00", }, }, }, } ts := &TimeSpan{ TimeStart: time.Date(2016, 1, 6, 23, 40, 0, 0, time.UTC), TimeEnd: time.Date(2016, 1, 7, 1, 1, 30, 0, time.UTC), } rIntervals := ri.SelectRatingIntevalsForTimespan(ts) if len(rIntervals) != 1 || rIntervals[0].Timing.StartTime != "19:00:00" { t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals)) } }
func TestTpActionTriggers(t *testing.T) { var atrs engine.ActionTriggers if err := tpRPC.Call("ApierV1.GetActionTriggers", v1.AttrGetActionTriggers{GroupIDs: []string{}}, &atrs); err != nil { t.Error("Got error on ApierV1.GetActionTriggers: ", err.Error()) } else if len(atrs) != 9 { t.Errorf("Calling v1.GetActionTriggers got: %v", atrs) } var reply string if err := tpRPC.Call("ApierV1.SetActionTrigger", v1.AttrSetActionTrigger{ GroupID: "TestATR", UniqueID: "Unique atr id", BalanceID: utils.StringPointer("BID1"), }, &reply); err != nil { t.Error("Got error on ApierV1.SetActionTrigger: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling v1.SetActionTrigger got: %v", reply) } if err := tpRPC.Call("ApierV1.GetActionTriggers", v1.AttrGetActionTriggers{GroupIDs: []string{}}, &atrs); err != nil { t.Error("Got error on ApierV1.GetActionTriggers: ", err.Error()) } else if len(atrs) != 10 { t.Errorf("Calling v1.GetActionTriggers got: %v", atrs) } if err := tpRPC.Call("ApierV1.GetActionTriggers", v1.AttrGetActionTriggers{GroupIDs: []string{"TestATR"}}, &atrs); err != nil { t.Error("Got error on ApierV1.GetActionTriggers: ", err.Error()) } else if len(atrs) != 1 { t.Errorf("Calling v1.GetActionTriggers got: %v", atrs) } if atrs[0].ID != "TestATR" || atrs[0].UniqueID != "Unique atr id" || *atrs[0].Balance.ID != "BID1" { t.Error("Wrong action trigger set: ", utils.ToIJSON(atrs[0])) } }
func TestDfGeneralJsonCfg(t *testing.T) { eCfg := &GeneralJsonCfg{ Instance_id: utils.StringPointer(""), Log_level: utils.IntPointer(utils.LOGLEVEL_INFO), Http_skip_tls_verify: utils.BoolPointer(false), Rounding_decimals: utils.IntPointer(5), Dbdata_encoding: utils.StringPointer("msgpack"), Tpexport_dir: utils.StringPointer("/var/spool/cgrates/tpe"), Httpposter_attempts: utils.IntPointer(3), Http_failed_dir: utils.StringPointer("/var/spool/cgrates/http_failed"), Default_request_type: utils.StringPointer(utils.META_RATED), Default_category: utils.StringPointer("call"), Default_tenant: utils.StringPointer("cgrates.org"), Default_timezone: utils.StringPointer("Local"), Connect_attempts: utils.IntPointer(3), Reconnects: utils.IntPointer(-1), Connect_timeout: utils.StringPointer("1s"), Reply_timeout: utils.StringPointer("2s"), Response_cache_ttl: utils.StringPointer("0s"), Internal_ttl: utils.StringPointer("2m"), Locking_timeout: utils.StringPointer("5s"), } if gCfg, err := dfCgrJsonCfg.GeneralJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, gCfg) { t.Error("Received: ", utils.ToIJSON(gCfg)) } }
func TestCacheJsonCfg(t *testing.T) { eCfg := &CacheJsonCfg{ Destinations: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Reverse_destinations: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Rating_plans: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(true)}, Rating_profiles: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Lcr: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Cdr_stats: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Actions: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Action_plans: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Action_triggers: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Shared_groups: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Aliases: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, Reverse_aliases: &CacheParamJsonCfg{Limit: utils.IntPointer(10000), Ttl: utils.StringPointer("0s"), Precache: utils.BoolPointer(false)}, } if gCfg, err := dfCgrJsonCfg.CacheJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, gCfg) { t.Error("Received: ", utils.ToIJSON(gCfg)) } }
func TestRatingProfileRISorter(t *testing.T) { ris := RateIntervalList{ &RateInterval{ Timing: &RITiming{ StartTime: "09:00:00", }, }, &RateInterval{ Timing: &RITiming{ StartTime: "00:00:00", }, }, &RateInterval{ Timing: &RITiming{ StartTime: "19:00:00", }, }, } sorter := &RateIntervalTimeSorter{referenceTime: time.Date(2016, 1, 6, 19, 0, 0, 0, time.UTC), ris: ris} rIntervals := sorter.Sort() if len(rIntervals) != 3 || rIntervals[0].Timing.StartTime != "00:00:00" || rIntervals[1].Timing.StartTime != "09:00:00" || rIntervals[2].Timing.StartTime != "19:00:00" { t.Error("Wrong interval list: ", utils.ToIJSON(rIntervals)) } }
func TestTpRemoveActionsRefenced(t *testing.T) { if !*testIntegration { return } // no more reference check for sake of speed! actionsMap := make(map[string]engine.Actions) if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{ ActionIDs: []string{"TOPUP_VOICE"}, }, &actionsMap); err != nil { t.Error("Got error on ApierV2.GetActions: ", err.Error()) } else if len(actionsMap) != 1 { t.Errorf("Calling ApierV2.GetActions got reply: %s", utils.ToIJSON(actionsMap)) } var reply string if err := tpRPC.Call("ApierV2.RemoveActions", v1.AttrRemoveActions{ ActionIDs: []string{"TOPUP_VOICE"}, }, &reply); err != nil { t.Error("Error on ApierV2.RemoveActions: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV2.RemoveActions got reply: %s", reply) } if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"}, }, &actionsMap); err == nil { t.Error("no error on ApierV2.GetActions: ", err) } }
func TestTpBalanceCounter(t *testing.T) { tStart := time.Date(2016, 3, 31, 0, 0, 0, 0, time.UTC) cd := engine.CallDescriptor{ Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "1001", Destination: "+49", DurationIndex: 0, TimeStart: tStart, TimeEnd: tStart.Add(time.Duration(20) * time.Second), } var cc engine.CallCost if err := tpRPC.Call("Responder.Debit", cd, &cc); err != nil { t.Error("Got error on Responder.GetCost: ", err.Error()) } else if cc.GetDuration() != 20*time.Second { t.Errorf("Calling Responder.MaxDebit got callcost: %v", cc.GetDuration()) } var acnt *engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"} if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error("Got error on ApierV2.GetAccount: ", err.Error()) } else if acnt.UnitCounters[utils.MONETARY][1].Counters[0].Value != 20.0 { t.Errorf("Calling ApierV2.GetBalance received: %s", utils.ToIJSON(acnt)) } }
func TestMaxDebitRatingInfoOnZeroTime(t *testing.T) { ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) for _, at := range ap { at.Execute() } cd := &CallDescriptor{ Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "dy", Account: "dy", Destination: "0723123113", TimeStart: time.Date(2015, 10, 26, 13, 29, 27, 0, time.UTC), TimeEnd: time.Date(2015, 10, 26, 13, 29, 27, 0, time.UTC), MaxCostSoFar: 0, } cc, err := cd.MaxDebit() if err != nil || len(cc.Timespans) != 1 || cc.Timespans[0].MatchedDestId != "RET" || cc.Timespans[0].MatchedSubject != "*out:cgrates.org:call:dy" || cc.Timespans[0].MatchedPrefix != "0723" || cc.Timespans[0].RatingPlanId != "DY_PLAN" { t.Error("MatchedInfo not added:", utils.ToIJSON(cc)) } }
func TestNewCgrJsonCfgFromFile(t *testing.T) { cgrJsonCfg, err := NewCgrJsonCfgFromFile("cfg_data.json") if err != nil { t.Error(err) } eCfg := &GeneralJsonCfg{Default_reqtype: utils.StringPointer(utils.META_PSEUDOPREPAID)} if gCfg, err := cgrJsonCfg.GeneralJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, gCfg) { t.Error("Received: ", gCfg) } cdrFields := []*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.TOR), Value: utils.StringPointer("~7:s/^(voice|data|sms|mms|generic)$/*$1/")}, &CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.ANSWER_TIME), Value: utils.StringPointer("1")}, &CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.USAGE), Value: utils.StringPointer(`~9:s/^(\d+)$/${1}s/`)}, } eCfgCdrc := map[string]*CdrcJsonCfg{ "CDRC-CSV1": &CdrcJsonCfg{ Enabled: utils.BoolPointer(true), Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc1/in"), Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc1/out"), Cdr_source_id: utils.StringPointer("csv1"), }, "CDRC-CSV2": &CdrcJsonCfg{ Enabled: utils.BoolPointer(true), Data_usage_multiply_factor: utils.Float64Pointer(0.000976563), Run_delay: utils.IntPointer(1), Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc2/in"), Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc2/out"), Cdr_source_id: utils.StringPointer("csv2"), Content_fields: &cdrFields, }, } if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfgCdrc, cfg) { t.Error("Received: ", utils.ToIJSON(cfg["CDRC-CSV2"])) } eCfgSmFs := &SmFsJsonCfg{ Enabled: utils.BoolPointer(true), Connections: &[]*FsConnJsonCfg{ &FsConnJsonCfg{ Server: utils.StringPointer("1.2.3.4:8021"), Password: utils.StringPointer("ClueCon"), Reconnects: utils.IntPointer(5), }, &FsConnJsonCfg{ Server: utils.StringPointer("2.3.4.5:8021"), Password: utils.StringPointer("ClueCon"), Reconnects: utils.IntPointer(5), }, }, } if smFsCfg, err := cgrJsonCfg.SmFsJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfgSmFs, smFsCfg) { t.Error("Received: ", smFsCfg) } }
func TestLoadAccountActions(t *testing.T) { if len(csvr.accountActions) != 17 { t.Error("Failed to load account actions: ", len(csvr.accountActions)) } aa := csvr.accountActions["vdf:minitsboy"] expected := &Account{ ID: "vdf:minitsboy", UnitCounters: UnitCounters{ utils.VOICE: []*UnitCounter{ &UnitCounter{ CounterType: "*event", Counters: CounterFilters{ &CounterFilter{ Value: 0, Filter: &BalanceFilter{ ID: utils.StringPointer("st0"), Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap("*out")), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")), SharedGroups: nil, Categories: nil, TimingIDs: nil, }, }, }, }, }, }, ActionTriggers: csvr.actionsTriggers["STANDARD_TRIGGER"], } // set propper uuid for i, atr := range aa.ActionTriggers { csvr.actionsTriggers["STANDARD_TRIGGER"][i].ID = atr.ID } for i, b := range aa.UnitCounters[utils.VOICE][0].Counters { expected.UnitCounters[utils.VOICE][0].Counters[i].Filter.ID = b.Filter.ID } if !reflect.DeepEqual(aa.UnitCounters[utils.VOICE][0].Counters[0], expected.UnitCounters[utils.VOICE][0].Counters[0]) { t.Errorf("Error loading account action: %+v", utils.ToIJSON(aa.UnitCounters[utils.VOICE][0].Counters[0].Filter)) } // test that it does not overwrite balances existing, err := accountingStorage.GetAccount(aa.ID) if err != nil || len(existing.BalanceMap) != 2 { t.Errorf("The account was not set before load: %+v", existing) } accountingStorage.SetAccount(aa) existing, err = accountingStorage.GetAccount(aa.ID) if err != nil || len(existing.BalanceMap) != 2 { t.Errorf("The set account altered the balances: %+v", existing) } }
func TestTpCreateExecuteActionMatch(t *testing.T) { if !*testIntegration { return } var reply string if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{ ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd", Actions: []*utils.TPAction{ &utils.TPAction{ BalanceType: "*monetary", Directions: "*out", Identifier: "*topup", RatingSubject: "", Units: "10.500000", Weight: 10, }, }, }, &reply); err != nil { t.Error("Got error on ApierV2.SetActions: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV2.SetActions got reply: %s", reply) } if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{ Tenant: "cgrates.org", Account: "1015", ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd", }, &reply); err != nil { t.Error("Got error on ApierV2.ExecuteAction: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ExecuteAction got reply: %s", reply) } if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{ Tenant: "cgrates.org", Account: "1015", ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd", }, &reply); err != nil { t.Error("Got error on ApierV2.ExecuteAction: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ExecuteAction got reply: %s", reply) } var acnt engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1015"} if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error("Got error on ApierV2.GetAccount: ", err.Error()) } if len(acnt.BalanceMap) != 1 || len(acnt.BalanceMap[utils.MONETARY]) != 1 || acnt.BalanceMap[utils.MONETARY].GetTotalValue() != 21 { t.Error("error matching previous created balance: ", utils.ToIJSON(acnt.BalanceMap)) } }
func TestLoadActionTriggers(t *testing.T) { if len(csvr.actionsTriggers) != 7 { t.Error("Failed to load action triggers: ", len(csvr.actionsTriggers)) } atr := csvr.actionsTriggers["STANDARD_TRIGGER"][0] expected := &ActionTrigger{ ID: "STANDARD_TRIGGER", UniqueID: "st0", ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ThresholdValue: 10, Balance: &BalanceFilter{ ID: nil, Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")), Categories: nil, TimingIDs: nil, SharedGroups: nil, Disabled: nil, Blocker: nil, }, Weight: 10, ActionsID: "SOME_1", Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Errorf("Error loading action trigger: %+v", utils.ToIJSON(atr.Balance)) } atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1] expected = &ActionTrigger{ ID: "STANDARD_TRIGGER", UniqueID: "st1", ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 200, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY")), Categories: nil, TimingIDs: nil, SharedGroups: nil, }, Weight: 10, ActionsID: "SOME_2", Executed: false, } if !reflect.DeepEqual(atr, expected) { t.Errorf("Error loading action trigger: %+v", atr) } }
func TestResponderGetSessionRuns(t *testing.T) { testTenant := "vdf" cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: "test", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), PDD: 3 * time.Second, AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Supplier: "suppl1", RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01} keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan2", "dan2") dfDC := &utils.DerivedCharger{RunID: utils.DEFAULT_RUNID, RequestTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: utils.META_DEFAULT, SubjectField: utils.META_DEFAULT, DestinationField: utils.META_DEFAULT, SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT} extra1DC := &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^" + utils.META_PREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: "^0", AccountField: "^minitsboy", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} extra2DC := &utils.DerivedCharger{RunID: "extra2", RequestTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "^ivo", SubjectField: "^ivo", DestinationField: utils.META_DEFAULT, SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} extra3DC := &utils.DerivedCharger{RunID: "extra3", RequestTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: "^0", AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT} charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{extra1DC, extra2DC, extra3DC}} if err := ratingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { t.Error("Error on setting DerivedChargers", err.Error()) } ratingStorage.CacheRatingAll("TestResponderGetSessionRuns") sesRuns := make([]*SessionRun, 0) eSRuns := []*SessionRun{ &SessionRun{DerivedCharger: extra1DC, CallDescriptor: &CallDescriptor{CgrID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), RunID: "extra1", Direction: "*out", Category: "0", Tenant: "vdf", Subject: "rif", Account: "minitsboy", Destination: "0256", TimeStart: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), TimeEnd: time.Date(2013, 11, 7, 8, 42, 36, 0, time.UTC), TOR: utils.VOICE, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}}}, &SessionRun{DerivedCharger: extra2DC, CallDescriptor: &CallDescriptor{CgrID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), RunID: "extra2", Direction: "*out", Category: "call", Tenant: "vdf", Subject: "ivo", Account: "ivo", Destination: "1002", TimeStart: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), TimeEnd: time.Date(2013, 11, 7, 8, 42, 36, 0, time.UTC), TOR: utils.VOICE, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}}}, &SessionRun{DerivedCharger: dfDC, CallDescriptor: &CallDescriptor{CgrID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), RunID: "*default", Direction: "*out", Category: "call", Tenant: "vdf", Subject: "dan2", Account: "dan2", Destination: "1002", TimeStart: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), TimeEnd: time.Date(2013, 11, 7, 8, 42, 36, 0, time.UTC), TOR: utils.VOICE, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}}}} if err := rsponder.GetSessionRuns(cdr, &sesRuns); err != nil { t.Error(err) } else if !reflect.DeepEqual(eSRuns, sesRuns) { for _, sr := range sesRuns { t.Logf("sr cd: %s", utils.ToIJSON(sr.CallDescriptor)) } t.Errorf("Expecting: %+v, received: %+v", eSRuns, sesRuns) } }
func testSMCosts(cfg *config.CGRConfig) error { if err := InitStorDb(cfg); err != nil { return err } cdrStorage, err := ConfigureCdrStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns, cfg.StorDBCDRSIndexes) if err != nil { return err } cc := &CallCost{ Direction: utils.OUT, Destination: "+4986517174963", Timespans: []*TimeSpan{ &TimeSpan{ TimeStart: time.Date(2015, 12, 28, 8, 53, 0, 0, time.UTC).Local(), // MongoDB saves timestamps in local timezone TimeEnd: time.Date(2015, 12, 28, 8, 54, 40, 0, time.UTC).Local(), DurationIndex: 0, RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, } if err := cdrStorage.SetSMCost(&SMCost{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", RunID: utils.META_DEFAULT, OriginHost: "localhost", OriginID: "12345", CostSource: utils.UNIT_TEST, CostDetails: cc}); err != nil { return err } if rcvSMC, err := cdrStorage.GetSMCosts("164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT, "", ""); err != nil { return err } else if len(rcvSMC) == 0 { return errors.New("No SMCosts received") } else if len(cc.Timespans) != len(rcvSMC[0].CostDetails.Timespans) { // cc.Timespans[0].RateInterval.Rating.Rates[0], rcvCC.Timespans[0].RateInterval.Rating.Rates[0]) return fmt.Errorf("Expecting: %+v, received: %+s", cc, utils.ToIJSON(rcvSMC[0])) } // Test query per prefix for i := 0; i < 3; i++ { if err := cdrStorage.SetSMCost(&SMCost{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e5" + strconv.Itoa(i), RunID: utils.META_DEFAULT, OriginHost: "localhost", OriginID: "abc" + strconv.Itoa(i), CostSource: utils.UNIT_TEST, CostDetails: cc}); err != nil { return err } } if rcvSMC, err := cdrStorage.GetSMCosts("", utils.META_DEFAULT, "localhost", "abc"); err != nil { return err } else if len(rcvSMC) != 3 { return fmt.Errorf("Expecting 3, received: %d", len(rcvSMC)) } return nil }
func TestMaxSesionTimeLongerThanMoney(t *testing.T) { cd := &CallDescriptor{ TimeStart: time.Date(2015, 07, 24, 13, 37, 0, 0, time.UTC), TimeEnd: time.Date(2015, 07, 24, 16, 37, 0, 0, time.UTC), Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "money", Destination: "0723", } acc, _ := accountingStorage.GetAccount("cgrates.org:money") allowedTime, err := cd.getMaxSessionDuration(acc) expected, err := time.ParseDuration("9999s") // 1 is the connect fee if err != nil || allowedTime != expected { t.Log(utils.ToIJSON(acc)) t.Errorf("Expected: %v got %v", expected, allowedTime) } }
func TestDestManagAllDestinationLoaded(t *testing.T) { if !*testIntegration { return } dests := make([]*engine.Destination, 0) if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil { t.Error("Got error on ApierV2.GetDestinations: ", err.Error()) } else if len(dests) != 6 { t.Errorf("Calling ApierV2.GetDestinations got reply: %v", utils.ToIJSON(dests)) } var rcvStats utils.CacheStats if err := destRPC.Call("ApierV1.GetCacheStats", utils.AttrCacheStats{}, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) } else if rcvStats.Destinations != 9 { t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats) } }
func TestTpSetRemoveActions(t *testing.T) { if !*testIntegration { return } var reply string if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{ ActionsId: "TO_BE_DELETED", Actions: []*utils.TPAction{ &utils.TPAction{ BalanceType: "*monetary", Directions: "*out", Identifier: "*topup", RatingSubject: "", Units: "10.500000", Weight: 10, }, }, }, &reply); err != nil { t.Error("Got error on ApierV2.SetActions: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV2.SetActions got reply: %s", reply) } actionsMap := make(map[string]engine.Actions) if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"}, }, &actionsMap); err != nil { t.Error("Got error on ApierV2.GetActions: ", err.Error()) } else if len(actionsMap) != 1 { t.Errorf("Calling ApierV2.GetActions got reply: %s", utils.ToIJSON(actionsMap)) } if err := tpRPC.Call("ApierV2.RemoveActions", v1.AttrRemoveActions{ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"}, }, &reply); err != nil { t.Error("Got error on ApierV2.RemoveActions: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV2.RemoveActions got reply: %s", reply) } if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"}, }, &actionsMap); err == nil { t.Error("no error on ApierV2.GetActions: ", err) } }
func TestGetCostRoundingIssue(t *testing.T) { ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) for _, at := range ap { at.Execute() } cd := &CallDescriptor{ Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "dy", Account: "dy", Destination: "0723123113", TimeStart: time.Date(2015, 10, 26, 13, 29, 27, 0, time.UTC), TimeEnd: time.Date(2015, 10, 26, 13, 29, 51, 0, time.UTC), MaxCostSoFar: 0, } cc, err := cd.GetCost() expected := 0.17 if cc.Cost != expected || err != nil { t.Log(utils.ToIJSON(cc)) t.Errorf("Expected %v was %+v", expected, cc) } }
func TestStatsAppendCdr(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), SetupTime: time.Now(), Usage: 10 * time.Second, Cost: 10, Supplier: "suppl1", DisconnectCause: "NORMAL_CLEARNING", } err := cdrStats.AppendCDR(cdr, nil) if err != nil { t.Error("Error appending cdr to stats: ", err) } t.Log(cdrStats.queues) if len(cdrStats.queues) != 5 || len(cdrStats.queues["CDRST1"].Cdrs) != 0 || len(cdrStats.queues["CDRST2"].Cdrs) != 1 { t.Error("Error appending cdr to queue: ", utils.ToIJSON(cdrStats.queues)) } }
func TestDfCdrcJsonCfg(t *testing.T) { eFields := []*CdrFieldJsonCfg{} cdrFields := []*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.TOR), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("2"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("3"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.REQTYPE), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("4"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Direction"), Field_id: utils.StringPointer(utils.DIRECTION), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("5"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"), Field_id: utils.StringPointer(utils.TENANT), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("6"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.CATEGORY), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("7"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.ACCOUNT), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("8"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.SUBJECT), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("9"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.DESTINATION), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("10"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SETUP_TIME), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("11"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.ANSWER_TIME), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("12"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.USAGE), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("13"), Mandatory: utils.BoolPointer(true)}, } cacheDumpFields := []*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Tag: utils.StringPointer("CGRID"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.CGRID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RunID"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.MEDI_RUNID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.TOR)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ACCID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.REQTYPE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Direction"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.DIRECTION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.TENANT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.CATEGORY)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ACCOUNT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.SUBJECT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.DESTINATION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.SETUP_TIME), Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ANSWER_TIME), Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.USAGE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.COST)}, } eCfg := []*CdrcJsonCfg{ &CdrcJsonCfg{ Id: utils.StringPointer(utils.META_DEFAULT), Enabled: utils.BoolPointer(false), Dry_run: utils.BoolPointer(false), Cdrs_conns: &[]*HaPoolJsonCfg{&HaPoolJsonCfg{ Address: utils.StringPointer(utils.MetaInternal), }}, Cdr_format: utils.StringPointer("csv"), Field_separator: utils.StringPointer(","), Timezone: utils.StringPointer(""), Run_delay: utils.IntPointer(0), Max_open_files: utils.IntPointer(1024), Data_usage_multiply_factor: utils.Float64Pointer(1024.0), Cdr_in_dir: utils.StringPointer("/var/spool/cgrates/cdrc/in"), Cdr_out_dir: utils.StringPointer("/var/spool/cgrates/cdrc/out"), Failed_calls_prefix: utils.StringPointer("missed_calls"), Cdr_path: utils.StringPointer(""), Cdr_source_id: utils.StringPointer("freeswitch_csv"), Cdr_filter: utils.StringPointer(""), Continue_on_success: utils.BoolPointer(false), Partial_record_cache: utils.StringPointer("10s"), Partial_cache_expiry_action: utils.StringPointer(utils.MetaDumpToFile), Header_fields: &eFields, Content_fields: &cdrFields, Trailer_fields: &eFields, Cache_dump_fields: &cacheDumpFields, }, } if cfg, err := dfCgrJsonCfg.CdrcJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { t.Errorf("Expecting: \n%s\n, received: \n%s\n: ", utils.ToIJSON(eCfg), utils.ToIJSON(cfg)) } }
func TestLoadRatingPlans(t *testing.T) { if len(csvr.ratingPlans) != 14 { t.Error("Failed to load rating plans: ", len(csvr.ratingPlans)) } rplan := csvr.ratingPlans["STANDARD"] expected := &RatingPlan{ Id: "STANDARD", Timings: map[string]*RITiming{ "59a981b9": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", tag: "WORKDAYS_00", }, "2d9ca6c4": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", tag: "WORKDAYS_18", }, "ec8ed374": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", tag: "WEEKENDS", }, "83429156": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{}, StartTime: "00:00:00", tag: "*any", }, }, Ratings: map[string]*RIRate{ "ebefae11": &RIRate{ ConnectFee: 0, Rates: []*Rate{ &Rate{ GroupIntervalStart: 0, Value: 0.2, RateIncrement: time.Second, RateUnit: time.Minute, }, }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, tag: "R1", }, "fac0138e": &RIRate{ ConnectFee: 0, Rates: []*Rate{ &Rate{ GroupIntervalStart: 0, Value: 0.1, RateIncrement: time.Second, RateUnit: time.Minute, }, }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, tag: "R2", }, "781bfa03": &RIRate{ ConnectFee: 0, Rates: []*Rate{ &Rate{ GroupIntervalStart: 0, Value: 0.05, RateIncrement: time.Second, RateUnit: time.Minute, }, }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, tag: "R3", }, "f692daa4": &RIRate{ ConnectFee: 0, Rates: []*Rate{ &Rate{ GroupIntervalStart: 0, Value: 0, RateIncrement: time.Second, RateUnit: time.Second, }, }, RoundingMethod: utils.ROUNDING_MIDDLE, RoundingDecimals: 4, tag: "R_URG", }, }, DestinationRates: map[string]RPRateList{ "GERMANY": []*RPRate{ &RPRate{ Timing: "ec8ed374", Rating: "ebefae11", Weight: 10, }, &RPRate{ Timing: "83429156", Rating: "fac0138e", Weight: 10, }, &RPRate{ Timing: "a60bfb13", Rating: "fac0138e", Weight: 10, }, }, "GERMANY_O2": []*RPRate{ &RPRate{ Timing: "ec8ed374", Rating: "fac0138e", Weight: 10, }, &RPRate{ Timing: "83429156", Rating: "781bfa03", Weight: 10, }, &RPRate{ Timing: "a60bfb13", Rating: "781bfa03", Weight: 10, }, }, "GERMANY_PREMIUM": []*RPRate{ &RPRate{ Timing: "ec8ed374", Rating: "16e9ee19", Weight: 10, }, }, "URG": []*RPRate{ &RPRate{ Timing: "2d9ca64", Rating: "f692daa4", Weight: 20, }, }, }, } if !reflect.DeepEqual(rplan.Ratings, expected.Ratings) { /*for tag, key := range rplan.Ratings { log.Print(tag, key) }*/ t.Errorf("Expecting: %s, received: %s", utils.ToIJSON(expected.Ratings), utils.ToIJSON(rplan.Ratings)) } anyTiming := &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{}, StartTime: "00:00:00", EndTime: "", cronString: "", tag: utils.ANY, } if !reflect.DeepEqual(csvr.ratingPlans["ANY_PLAN"].Timings["1323e132"], anyTiming) { t.Errorf("Error using *any timing in rating plans: %+v : %+v", csvr.ratingPlans["ANY_PLAN"].Timings["1323e132"], anyTiming) } }
func TestLoadActions(t *testing.T) { if len(csvr.actions) != 16 { t.Error("Failed to load actions: ", len(csvr.actions)) } as1 := csvr.actions["MINI"] expected := []*Action{ &Action{ Id: "MINI", ActionType: TOPUP_RESET, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Uuid: as1[0].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 10}, Weight: utils.Float64Pointer(10), DestinationIDs: nil, TimingIDs: nil, SharedGroups: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, &Action{ Id: "MINI", ActionType: TOPUP, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Uuid: as1[1].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 100}, Weight: utils.Float64Pointer(10), RatingSubject: utils.StringPointer("test"), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), TimingIDs: nil, SharedGroups: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as1, expected) { t.Errorf("Error loading action1: %s", utils.ToIJSON(as1)) } as2 := csvr.actions["SHARED"] expected = []*Action{ &Action{ Id: "SHARED", ActionType: TOPUP, ExpirationString: UNLIMITED, Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIDs: nil, Uuid: as2[0].Balance.Uuid, Value: &utils.ValueFormula{Static: 100}, Weight: utils.Float64Pointer(10), SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")), TimingIDs: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as2, expected) { t.Errorf("Error loading action: %s", utils.ToIJSON(as2)) } as3 := csvr.actions["DEFEE"] expected = []*Action{ &Action{ Id: "DEFEE", ActionType: CDRLOG, ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`, Weight: 10, Balance: &BalanceFilter{ Uuid: as3[0].Balance.Uuid, Directions: nil, DestinationIDs: nil, TimingIDs: nil, Categories: nil, SharedGroups: nil, Blocker: utils.BoolPointer(false), Disabled: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as3, expected) { t.Errorf("Error loading action: %+v", as3[0].Balance) } asGnrc := csvr.actions["TOPUP_RST_GNR_1000"] //TOPUP_RST_GNR_1000,*topup_reset,"{""*voice"": 60.0,""*data"":1024.0,""*sms"":1.0}",,,*generic,*out,,*any,,,*unlimited,,1000,20,false,false,10 expected = []*Action{ &Action{ Id: "TOPUP_RST_GNR_1000", ActionType: TOPUP_RESET, ExtraParameters: `{"*voice": 60.0,"*data":1024.0,"*sms":1.0}`, Weight: 10, ExpirationString: utils.UNLIMITED, Balance: &BalanceFilter{ Uuid: asGnrc[0].Balance.Uuid, Type: utils.StringPointer(utils.GENERIC), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), //DestinationIDs: utils.StringMapPointer(utils.NewStringMap("*any")), Value: &utils.ValueFormula{Static: 1000}, Weight: utils.Float64Pointer(20), Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(asGnrc, expected) { t.Errorf("Expecting: %+v, received: %+v", expected[0].Balance, asGnrc[0].Balance) } }
func TestDestManagCacheWithGetCost(t *testing.T) { if !*testIntegration { return } if err := engine.InitDataDb(destCfg); err != nil { t.Fatal(err) } var reply string if err := destRPC.Call("ApierV1.ReloadCache", utils.AttrReloadCache{}, &reply); err != nil { t.Error("Got error on ApierV1.ReloadCache: ", err.Error()) } else if reply != utils.OK { t.Errorf("Calling ApierV1.ReloadCache received: %+v", reply) } attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "cacheall"), FlushDb: true} if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil { t.Error(err) } else if destLoadInst.RatingLoadID == "" || destLoadInst.AccountingLoadID == "" { t.Error("Empty loadId received, loadInstance: ", destLoadInst) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups dests := make([]*engine.Destination, 0) if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil { t.Error("Got error on ApierV2.GetDestinations: ", err.Error()) } else if len(dests) != 1 { t.Errorf("Calling ApierV2.GetDestinations got reply: %v", utils.ToIJSON(dests)) } var cc engine.CallCost cd := &engine.CallDescriptor{ Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "test", Destination: "1002", TimeStart: time.Date(2016, 2, 24, 0, 0, 0, 0, time.UTC), TimeEnd: time.Date(2016, 2, 24, 0, 0, 10, 0, time.UTC), } if err := destRPC.Call("Responder.GetCost", cd, &cc); err != nil { t.Error(err) } else if cc.Cost != 1.6667 { t.Error("Empty loadId received, loadInstance: ", utils.ToIJSON(cc)) } attrs = &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "cacheone"), FlushDb: true} if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil { t.Error(err) } else if destLoadInst.RatingLoadID == "" || destLoadInst.AccountingLoadID == "" { t.Error("Empty loadId received, loadInstance: ", destLoadInst) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups dests = make([]*engine.Destination, 0) if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil { t.Error("Got error on ApierV2.GetDestinations: ", err.Error()) } else if len(dests) != 1 { t.Errorf("Calling ApierV2.GetDestinations got reply: %v", utils.ToIJSON(dests)) } if err := destRPC.Call("Responder.GetCost", cd, &cc); err.Error() != utils.ErrUnauthorizedDestination.Error() { t.Error(err) } }
func TestLCRCostSuppliersLoadAllOverMisingParams(t *testing.T) { setupTime := time.Date(2015, 7, 31, 6, 43, 0, 0, time.UTC) lcrCost := &LCRCost{ Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_LOAD, StrategyParams: "", Weight: 10.0}, SupplierCosts: []*LCRSupplierCost{ &LCRSupplierCost{ Supplier: "*out:tenant12:call:ivo12", supplierQueues: []*StatsQueue{ &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 3 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 1 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, }, }, }, }, &LCRSupplierCost{ Supplier: "*out:tenant12:call:dan12", supplierQueues: []*StatsQueue{ &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{SetupTime: setupTime.Add(60 * time.Minute)}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{}, &QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, }, }, &LCRSupplierCost{ Supplier: "*out:tenant12:call:rif12", supplierQueues: []*StatsQueue{ &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 7 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{}, &QCdr{SetupTime: setupTime.Add(200 * time.Minute)}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 10 * time.Minute, }, }, &StatsQueue{ Cdrs: []*QCdr{&QCdr{}, &QCdr{SetupTime: setupTime}}, conf: &CdrStats{ QueueLength: 0, TimeWindow: 1 * time.Minute, }, }, }, }, }, } lcrCost.Sort() if len(lcrCost.SupplierCosts) != 3 { t.Error("Error soring on load distribution: ", utils.ToIJSON(lcrCost)) } }
func TestLoadActions(t *testing.T) { if len(csvr.actions) != 15 { t.Error("Failed to load actions: ", len(csvr.actions)) } as1 := csvr.actions["MINI"] expected := []*Action{ &Action{ Id: "MINI", ActionType: TOPUP_RESET, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Uuid: as1[0].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 10}, Weight: utils.Float64Pointer(10), DestinationIDs: nil, TimingIDs: nil, SharedGroups: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, &Action{ Id: "MINI", ActionType: TOPUP, ExpirationString: UNLIMITED, ExtraParameters: "", Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Uuid: as1[1].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 100}, Weight: utils.Float64Pointer(10), RatingSubject: utils.StringPointer("test"), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), TimingIDs: nil, SharedGroups: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as1, expected) { t.Errorf("Error loading action1: %s", utils.ToIJSON(as1)) } as2 := csvr.actions["SHARED"] expected = []*Action{ &Action{ Id: "SHARED", ActionType: TOPUP, ExpirationString: UNLIMITED, Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), DestinationIDs: nil, Uuid: as2[0].Balance.Uuid, Value: &utils.ValueFormula{Static: 100}, Weight: utils.Float64Pointer(10), SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")), TimingIDs: nil, Categories: nil, Disabled: utils.BoolPointer(false), Blocker: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as2, expected) { t.Errorf("Error loading action: %s", utils.ToIJSON(as2)) } as3 := csvr.actions["DEFEE"] expected = []*Action{ &Action{ Id: "DEFEE", ActionType: CDRLOG, ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`, Weight: 10, Balance: &BalanceFilter{ Uuid: as3[0].Balance.Uuid, Directions: nil, DestinationIDs: nil, TimingIDs: nil, Categories: nil, SharedGroups: nil, Blocker: utils.BoolPointer(false), Disabled: utils.BoolPointer(false), }, }, } if !reflect.DeepEqual(as3, expected) { t.Errorf("Error loading action: %+v", as3[0].Balance) } }