From b012922272fb89cef0234df7f9782169a49ade89 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 30 Jul 2014 14:23:31 +0300 Subject: [PATCH] test for cdr stats csv load --- .../prepaid1centpsec/ActionTriggers.csv | 13 ++-- data/tariffplans/prepaid1centpsec/Actions.csv | 1 + .../tariffplans/prepaid1centpsec/CdrStats.csv | 6 ++ engine/loader_csv.go | 12 ++-- engine/loader_csv_test.go | 64 +++++++++++++++---- engine/loader_helpers.go | 20 +++--- utils/consts.go | 4 +- 7 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 data/tariffplans/prepaid1centpsec/CdrStats.csv diff --git a/data/tariffplans/prepaid1centpsec/ActionTriggers.csv b/data/tariffplans/prepaid1centpsec/ActionTriggers.csv index cbae2ced0..27d629601 100644 --- a/data/tariffplans/prepaid1centpsec/ActionTriggers.csv +++ b/data/tariffplans/prepaid1centpsec/ActionTriggers.csv @@ -1,4 +1,9 @@ -#Tag,BalanceType,Direction,ThresholdType,ThresholdValue,Recurrent,DestinationTag,ActionsTag,Weight -STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,false,,LOG_BALANCE,10 -STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,false,,LOG_BALANCE,10 -STANDARD_TRIGGERS,*monetary,*out,*max_counter,15,false,FS_USERS,LOG_BALANCE,10 +#Tag,BalanceTag,Direction,ThresholdType,ThresholdValue,Recurrent,MinSleep,BalanceDestinationTag,BalanceWeight,BalanceExpiryTime,BalanceRatingSubject,BalanceSharedGroup,StatsMinQueuedItems,ActionsTag,Weight +STANDARD_TRIGGERS,*monetary,*out,*min_balance,2,false,0,,,,,,,LOG_BALANCE,10 +STANDARD_TRIGGERS,*monetary,*out,*max_balance,20,false,0,,,,,,,LOG_BALANCE,10 +STANDARD_TRIGGERS,*monetary,*out,*max_counter,15,false,0,FS_USERS,,,,,,LOG_BALANCE,10 +CDRST1_WARN_ASR,,,*min_asr,45,true,1h,,,,,,3,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACD,,,*min_acd,10,true,1h,,,,,,5,CDRST_WARN_HTTP,10 +CDRST1_WARN_ACC,,,*max_acc,10,true,10m,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ASR,,,*min_asr,30,true,,,,,,,5,CDRST_WARN_HTTP,10 +CDRST2_WARN_ACD,,,*min_acd,3,true,,,,,,,5,CDRST_WARN_HTTP,10 diff --git a/data/tariffplans/prepaid1centpsec/Actions.csv b/data/tariffplans/prepaid1centpsec/Actions.csv index 946b391e8..299a07a4b 100644 --- a/data/tariffplans/prepaid1centpsec/Actions.csv +++ b/data/tariffplans/prepaid1centpsec/Actions.csv @@ -2,3 +2,4 @@ PREPAID_10,*topup_reset,*monetary,*out,10,*unlimited,*any,,10,,,10 BONUS_1,*topup,*monetary,*out,1,*unlimited,*any,,10,,,10 LOG_BALANCE,*log,,,,,,,,,,10 +CDRST_WARN_HTTP,*call_url,,,,,,,,,http://localhost:8080,10 \ No newline at end of file diff --git a/data/tariffplans/prepaid1centpsec/CdrStats.csv b/data/tariffplans/prepaid1centpsec/CdrStats.csv new file mode 100644 index 000000000..d17db8bed --- /dev/null +++ b/data/tariffplans/prepaid1centpsec/CdrStats.csv @@ -0,0 +1,6 @@ +#Id,QueueLength,TimeWindow,Metrics,SetupInterval,TOR,CdrHost,CdrSource,ReqType,Direction,Tenant,Category,Account,Subject,DestinationPrefix,UsageInterval,MediationRunIds,RatedAccount,RatedSubject,CostInterval,Triggers +CDRST1,5,60m,ASR,2014-07-29T15:00:00Z;2014-07-29T16:00:00Z,*voice,87.139.12.167,FS_JSON,rated,*out,cgrates.org,call,dan,dan,49,5m;10m,default,rif,rif,0;2,CDRST1_WARN_ASR +CDRST1,,,ACD,,,,,,,,,,,,,,,,,CDRST1_WARN_ACD +CDRST1,,,ACC,,,,,,,,,,,,,,,,,CDRST1_WARN_ACC +CDRST2,10,10m,ASR,,,,,,,cgrates.org,call,,,,,,,,,CDRST2_WARN_ASR +CDRST2,,,ACD,,,,,,,,,,,,,,,,,CDRST2_WARN_ACD \ No newline at end of file diff --git a/engine/loader_csv.go b/engine/loader_csv.go index 7d4d37260..49906960f 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -914,7 +914,7 @@ func (csvr *CSVReader) LoadDerivedChargers() (err error) { } func (csvr *CSVReader) LoadCdrStats() (err error) { - csvReader, fp, err := csvr.readerFunc(csvr.timingsFn, csvr.sep, utils.TIMINGS_NRCOLS) + csvReader, fp, err := csvr.readerFunc(csvr.cdrStatsFn, csvr.sep, utils.CDR_STATS_NRCOLS) if err != nil { log.Print("Could not load cdr stats file: ", err) // allow writing of the other values @@ -925,18 +925,16 @@ func (csvr *CSVReader) LoadCdrStats() (err error) { } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tag := record[0] - if _, exists := csvr.cdrStats[tag]; exists { - log.Print("Warning: duplicate cdr stats found: ", tag) - } var cs *CdrStats var exists bool if cs, exists = csvr.cdrStats[tag]; !exists { cs = &CdrStats{} } - triggers, exists := csvr.actionsTriggers[record[18]] - if record[18] != "" && !exists { + triggerTag := record[20] + triggers, exists := csvr.actionsTriggers[triggerTag] + if triggerTag != "" && !exists { // only return error if there was something there for the tag - return fmt.Errorf("Could not get action triggers for cdr stats id %s: %s", cs.Id, record[18]) + return fmt.Errorf("Could not get action triggers for cdr stats id %s: %s", cs.Id, triggerTag) } UpdateCdrStats(cs, triggers, record...) csvr.cdrStats[tag] = cs diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 69b07ea9d..4a49e422a 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -183,6 +183,12 @@ vdf,emptyY,*out,TOPUP_EMPTY_AT, *out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,, ` cdrStats = ` +#Id,QueueLength,TimeWindow,Metrics,SetupInterval,TOR,CdrHost,CdrSource,ReqType,Direction,Tenant,Category,Account,Subject,DestinationPrefix,UsageInterval,MediationRunIds,RatedAccount,RatedSubject,CostInterval,Triggers +CDRST1,5,60m,ASR,2014-07-29T15:00:00Z;2014-07-29T16:00:00Z,*voice,87.139.12.167,FS_JSON,rated,*out,cgrates.org,call,dan,dan,49,5m;10m,default,rif,rif,0;2,STANDARD_TRIGGERS +CDRST1,,,ACD,,,,,,,,,,,,,,,,,STANDARD_TRIGGER +CDRST1,,,ACC,,,,,,,,,,,,,,,,, +CDRST2,10,10m,ASR,,,,,,,cgrates.org,call,,,,,,,,, +CDRST2,,,ACD,,,,,,,,,,,,,,,,, ` ) @@ -204,6 +210,7 @@ func init() { csvr.LoadActionTriggers() csvr.LoadAccountActions() csvr.LoadDerivedChargers() + csvr.LoadCdrStats() csvr.WriteToDatabase(false, false) dataStorage.CacheRating(nil, nil, nil, nil, nil) accountingStorage.CacheAccounting(nil, nil, nil, nil) @@ -770,19 +777,19 @@ func TestLoadSharedGroups(t *testing.T) { t.Error("Error loading shared group: ", sg2.AccountParameters) } /*sg, _ := accountingStorage.GetSharedGroup("SG1", false) - if len(sg.Members) != 0 { - t.Errorf("Memebers should be empty: %+v", sg) - } + if len(sg.Members) != 0 { + t.Errorf("Memebers should be empty: %+v", sg) + } - // execute action timings to fill memebers - atm := csvr.actionsTimings["MORE_MINUTES"][1] - atm.Execute() - atm.actions, atm.stCache = nil, time.Time{} + // execute action timings to fill memebers + atm := csvr.actionsTimings["MORE_MINUTES"][1] + atm.Execute() + atm.actions, atm.stCache = nil, time.Time{} - sg, _ = accountingStorage.GetSharedGroup("SG1", false) - if len(sg.Members) != 1 { - t.Errorf("Memebers should not be empty: %+v", sg) - }*/ + sg, _ = accountingStorage.GetSharedGroup("SG1", false) + if len(sg.Members) != 1 { + t.Errorf("Memebers should not be empty: %+v", sg) + }*/ } func TestLoadLCRs(t *testing.T) { @@ -945,3 +952,38 @@ func TestLoadDerivedChargers(t *testing.T) { t.Error("Unexpected charger", csvr.derivedChargers[keyCharger1]) } } +func TestLoadCdrStats(t *testing.T) { + if len(csvr.cdrStats) != 2 { + t.Error("Failed to load cdr stats: ", csvr.cdrStats) + } + cdrStats1 := &CdrStats{ + Id: "CDRST1", + QueueLength: 5, + TimeWindow: 60 * time.Minute, + Metrics: []string{"ASR", "ACD", "ACC"}, + SetupInterval: []time.Time{ + time.Date(2014, 7, 29, 15, 0, 0, 0, time.UTC), + time.Date(2014, 7, 29, 16, 0, 0, 0, time.UTC), + }, + TOR: []string{utils.VOICE}, + CdrHost: []string{"87.139.12.167"}, + CdrSource: []string{"FS_JSON"}, + ReqType: []string{"rated"}, + Direction: []string{utils.OUT}, + Tenant: []string{"cgrates.org"}, + Category: []string{"call"}, + Account: []string{"dan"}, + Subject: []string{"dan"}, + DestinationPrefix: []string{"49"}, + UsageInterval: []time.Duration{5 * time.Minute, 10 * time.Minute}, + MediationRunIds: []string{"default"}, + RatedAccount: []string{"rif"}, + RatedSubject: []string{"rif"}, + CostInterval: []float64{0, 2}, + } + cdrStats1.Triggers = append(cdrStats1.Triggers, csvr.actionsTriggers["STANDARD_TRIGGERS"]...) + cdrStats1.Triggers = append(cdrStats1.Triggers, csvr.actionsTriggers["STANDARD_TRIGGER"]...) + if !reflect.DeepEqual(csvr.cdrStats[cdrStats1.Id], cdrStats1) { + t.Error("Unexpected stats", csvr.cdrStats[cdrStats1.Id]) + } +} diff --git a/engine/loader_helpers.go b/engine/loader_helpers.go index 71f949ffe..95ca67263 100644 --- a/engine/loader_helpers.go +++ b/engine/loader_helpers.go @@ -97,13 +97,12 @@ func NewTiming(timingInfo ...string) (rt *utils.TPTiming) { } func UpdateCdrStats(cs *CdrStats, triggers ActionTriggerPriotityList, record ...string) { - cs = &CdrStats{} cs.Id = record[0] if record[1] != "" { if qi, err := strconv.Atoi(record[1]); err == nil { cs.QueueLength = qi } else { - log.Printf("Error parsing QueuedItems %v for cdrs stats %v", record[1], cs.Id) + log.Printf("Error parsing QueuedLength %v for cdrs stats %v", record[1], cs.Id) } } if record[2] != "" { @@ -200,7 +199,13 @@ func UpdateCdrStats(cs *CdrStats, triggers ActionTriggerPriotityList, record ... cs.MediationRunIds = append(cs.MediationRunIds, record[16]) } if record[17] != "" { - costs := strings.Split(record[17], utils.INFIELD_SEP) + cs.RatedAccount = append(cs.RatedAccount, record[17]) + } + if record[18] != "" { + cs.RatedSubject = append(cs.RatedSubject, record[18]) + } + if record[19] != "" { + costs := strings.Split(record[19], utils.INFIELD_SEP) if len(costs) > 0 { if sCost, err := strconv.ParseFloat(costs[0], 64); err == nil { if len(cs.CostInterval) < 1 { @@ -209,7 +214,7 @@ func UpdateCdrStats(cs *CdrStats, triggers ActionTriggerPriotityList, record ... cs.CostInterval[0] = sCost } } else { - log.Printf("Error parsing CostInterval %v for cdrs stats %v", record[17], cs.Id) + log.Printf("Error parsing CostInterval %v for cdrs stats %v", record[19], cs.Id) } } if len(costs) > 1 { @@ -220,13 +225,12 @@ func UpdateCdrStats(cs *CdrStats, triggers ActionTriggerPriotityList, record ... cs.CostInterval[1] = eCost } } else { - log.Printf("Error parsing CostInterval %v for cdrs stats %v", record[17], cs.Id) + log.Printf("Error parsing CostInterval %v for cdrs stats %v", record[19], cs.Id) } } } - if triggers != nil { - cs.Triggers = triggers + cs.Triggers = append(cs.Triggers, triggers...) } } @@ -337,7 +341,7 @@ var FileValidators = map[string]*FileLineRegexValidator{ regexp.MustCompile(`(?:\w+\s*,\s*){3}(?:\d+\.?\d*){1}`), "Tag([0-9A-Za-z_]),ActionsTag([0-9A-Za-z_]),TimingTag([0-9A-Za-z_]),Weight([0-9.])"}, utils.ACTION_TRIGGERS_CSV: &FileLineRegexValidator{utils.ACTION_TRIGGERS_NRCOLS, - regexp.MustCompile(`(?:\w+),(?:\*\w+),(?:\*out),(?:\*\w+),(?:\d+\.?\d*),(?:true|false)?,(?:\w+|\*any)?,(?:\w+),(?:\d+\.?\d*)$`), + regexp.MustCompile(`(?:\w+),(?:\*\w+),(?:\*out),(?:\*\w+),(?:\d+\.?\d*),(?:true|false)?,(?:\d+),(?:\w+|\*any)?,(?:\d+\.?\d*)?,(?:\*\w+\s*|\+\d+[smh]\s*|\d+\s*)?,(?:\w+|\*any)?,(?:\w+|\*any)?,(?:\d+),(?:\w+),(?:\d+\.?\d*)$`), "Tag([0-9A-Za-z_]),BalanceType(*[a-z_]),Direction(*out),ThresholdType(*[a-z_]),ThresholdValue([0-9]+),Recurrent(true|false),DestinationTag([0-9A-Za-z_]|*all),ActionsTag([0-9A-Za-z_]),Weight([0-9]+)"}, utils.ACCOUNT_ACTIONS_CSV: &FileLineRegexValidator{utils.ACCOUNT_ACTIONS_NRCOLS, regexp.MustCompile(`(?:\w+\s*),(?:(\w+;?)+\s*),(?:\*out\s*),(?:\w+\s*),(?:\w+\s*)$`), diff --git a/utils/consts.go b/utils/consts.go index 7e385f7b2..a809f7ea5 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -50,7 +50,7 @@ const ( ACTION_TRIGGERS_CSV = "ActionTriggers.csv" ACCOUNT_ACTIONS_CSV = "AccountActions.csv" DERIVED_CHARGERS_CSV = "DerivedChargers.csv" - CDR_STATS_CSV = "CdrStats.csv" + CDR_STATS_CSV = "CdrStats.csv" TIMINGS_NRCOLS = 6 DESTINATIONS_NRCOLS = 2 RATES_NRCOLS = 6 @@ -64,7 +64,7 @@ const ( ACTION_TRIGGERS_NRCOLS = 15 ACCOUNT_ACTIONS_NRCOLS = 5 DERIVED_CHARGERS_NRCOLS = 17 - CDR_STATS_NRCOLS = 19 + CDR_STATS_NRCOLS = 21 ROUNDING_UP = "*up" ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down"