From 82be280d0a053990d4ad1849807c52ce7a4c6286 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 13:05:02 +0200 Subject: [PATCH 1/3] Removing Quotes from data/storage --- data/storage/mysql/create_cdrs_tables.sql | 8 ++++---- data/storage/postgres/create_cdrs_tables.sql | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql index 5f0b2b673..c424c9e94 100644 --- a/data/storage/mysql/create_cdrs_tables.sql +++ b/data/storage/mysql/create_cdrs_tables.sql @@ -5,7 +5,7 @@ DROP TABLE IF EXISTS cdrs; CREATE TABLE cdrs ( id int(11) NOT NULL AUTO_INCREMENT, - `cgrid` varchar(40) NOT NULL, + cgrid varchar(40) NOT NULL, run_id varchar(64) NOT NULL, origin_host varchar(64) NOT NULL, source varchar(64) NOT NULL, @@ -29,13 +29,13 @@ CREATE TABLE cdrs ( updated_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, PRIMARY KEY (id), - UNIQUE KEY cdrrun (`cgrid`, run_id, origin_id) + UNIQUE KEY cdrrun (cgrid, run_id, origin_id) ); DROP TABLE IF EXISTS sm_costs; CREATE TABLE sm_costs ( id int(11) NOT NULL AUTO_INCREMENT, - `cgrid` varchar(40) NOT NULL, + cgrid varchar(40) NOT NULL, run_id varchar(64) NOT NULL, origin_host varchar(64) NOT NULL, origin_id varchar(64) NOT NULL, @@ -45,7 +45,7 @@ CREATE TABLE sm_costs ( created_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, PRIMARY KEY (`id`), - UNIQUE KEY costid (`cgrid`, run_id), + UNIQUE KEY costid (cgrid, run_id), KEY origin_idx (origin_host, origin_id), KEY run_origin_idx (run_id, origin_id), KEY deleted_at_idx (deleted_at) diff --git a/data/storage/postgres/create_cdrs_tables.sql b/data/storage/postgres/create_cdrs_tables.sql index d144f9890..ad565c068 100644 --- a/data/storage/postgres/create_cdrs_tables.sql +++ b/data/storage/postgres/create_cdrs_tables.sql @@ -5,7 +5,7 @@ DROP TABLE IF EXISTS cdrs; CREATE TABLE cdrs ( id SERIAL PRIMARY KEY, - "cgrid" VARCHAR(40) NOT NULL, + cgrid VARCHAR(40) NOT NULL, run_id VARCHAR(64) NOT NULL, origin_host VARCHAR(64) NOT NULL, source VARCHAR(64) NOT NULL, @@ -28,7 +28,7 @@ CREATE TABLE cdrs ( created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE NULL, deleted_at TIMESTAMP WITH TIME ZONE NULL, - UNIQUE ("cgrid", run_id, origin_id) + UNIQUE (cgrid, run_id, origin_id) ); ; DROP INDEX IF EXISTS deleted_at_cp_idx; @@ -38,7 +38,7 @@ CREATE INDEX deleted_at_cp_idx ON cdrs (deleted_at); DROP TABLE IF EXISTS sm_costs; CREATE TABLE sm_costs ( id SERIAL PRIMARY KEY, - "cgrid" VARCHAR(40) NOT NULL, + cgrid VARCHAR(40) NOT NULL, run_id VARCHAR(64) NOT NULL, origin_host VARCHAR(64) NOT NULL, origin_id VARCHAR(64) NOT NULL, @@ -47,10 +47,10 @@ CREATE TABLE sm_costs ( cost_details jsonb, created_at TIMESTAMP WITH TIME ZONE, deleted_at TIMESTAMP WITH TIME ZONE NULL, - UNIQUE ("cgrid", run_id) + UNIQUE (cgrid, run_id) ); DROP INDEX IF EXISTS cgrid_smcost_idx; -CREATE INDEX cgrid_smcost_idx ON sm_costs ("cgrid", run_id); +CREATE INDEX cgrid_smcost_idx ON sm_costs (cgrid, run_id); DROP INDEX IF EXISTS origin_smcost_idx; CREATE INDEX origin_smcost_idx ON sm_costs (origin_host, origin_id); DROP INDEX IF EXISTS run_origin_smcost_idx; From 6bf57b827dd130d2f520618f3f4e0419433b4f8e Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 31 Oct 2017 17:08:43 +0100 Subject: [PATCH 2/3] Replacing ParseDurationWithSecs with ParseDurationWithNanosecs in most of the places to allow data units parsing without conversion; tests updated --- apier/v1/triggers.go | 4 ++-- apier/v2/triggers.go | 2 +- cdrc/csv_test.go | 33 ++++++++++++++++++---------- cdrc/xml.go | 16 ++++++++------ cdrc/xml_test.go | 8 +++++-- cmd/cgr-engine/cgr-engine.go | 2 +- cmd/cgr-tester/cgr-tester.go | 2 +- config/cacheconfig.go | 2 +- config/cdrcconfig.go | 2 +- config/config.go | 14 ++++++------ config/daconfig.go | 2 +- config/reslimitercfg.go | 2 +- config/smconfig.go | 38 ++++++++++++++++----------------- config/statscfg.go | 2 +- config/thresholdscfg.go | 2 +- engine/action.go | 4 +++- engine/cdr.go | 14 ++++++------ engine/cdr_test.go | 10 ++++----- engine/cgrcdr.go | 2 +- engine/cgrcdr_test.go | 4 ++-- engine/lcr.go | 14 ++++++------ engine/lcr_test.go | 4 ++-- engine/libstats.go | 4 ++-- engine/loader_csv_test.go | 36 +++++++++++++++---------------- engine/model_helpers.go | 6 +++--- engine/model_helpers_test.go | 4 ++-- engine/responder.go | 2 +- engine/storage_mongo_stordb.go | 8 +++---- engine/tp_reader.go | 6 +++--- general_tests/datachrg1_test.go | 4 ++-- general_tests/smschrg1_test.go | 2 +- sessionmanager/smg_event.go | 16 +++++++------- utils/apitpdata.go | 6 +++--- 33 files changed, 148 insertions(+), 129 deletions(-) diff --git a/apier/v1/triggers.go b/apier/v1/triggers.go index 7ceb17094..ad4c74460 100644 --- a/apier/v1/triggers.go +++ b/apier/v1/triggers.go @@ -254,7 +254,7 @@ func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers, at.Executed = *attr.Executed } if attr.MinSleep != nil { - minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep) + minSleep, err := utils.ParseDurationWithNanosecs(*attr.MinSleep) if err != nil { return 0, err } @@ -443,7 +443,7 @@ func (self *ApierV1) SetActionTrigger(attr AttrSetActionTrigger, reply *string) newAtr.Recurrent = *attr.Recurrent } if attr.MinSleep != nil { - minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep) + minSleep, err := utils.ParseDurationWithNanosecs(*attr.MinSleep) if err != nil { *reply = err.Error() return err diff --git a/apier/v2/triggers.go b/apier/v2/triggers.go index 9edb7a6e0..5a93919de 100644 --- a/apier/v2/triggers.go +++ b/apier/v2/triggers.go @@ -88,7 +88,7 @@ func (attr *AttrSetAccountActionTriggers) UpdateActionTrigger(at *engine.ActionT at.Executed = *attr.Executed } if attr.MinSleep != nil { - if at.MinSleep, err = utils.ParseDurationWithSecs(*attr.MinSleep); err != nil { + if at.MinSleep, err = utils.ParseDurationWithNanosecs(*attr.MinSleep); err != nil { return } } diff --git a/cdrc/csv_test.go b/cdrc/csv_test.go index a207ab1dd..36fa36340 100644 --- a/cdrc/csv_test.go +++ b/cdrc/csv_test.go @@ -40,7 +40,7 @@ func TestCsvRecordToCDR(t *testing.T) { t.Error("Failed to corectly detect missing fields from record") } cdrRow = []string{"ignored", "ignored", utils.VOICE, "acc1", utils.META_PREPAID, "*out", "cgrates.org", "call", "1001", "1001", "+4986517174963", - "2013-02-03 19:50:00", "2013-02-03 19:54:00", "62", "supplier1", "172.16.1.1", "NORMAL_DISCONNECT"} + "2013-02-03 19:50:00", "2013-02-03 19:54:00", "62s", "supplier1", "172.16.1.1", "NORMAL_DISCONNECT"} rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig) if err != nil { t.Error("Failed to parse CDR in rated cdr", err) @@ -88,7 +88,7 @@ func TestCsvDataMultiplyFactor(t *testing.T) { ToR: cdrRow[0], OriginHost: "0.0.0.0", Source: "TEST_CDRC", - Usage: time.Duration(1) * time.Second, + Usage: time.Duration(1), ExtraFields: map[string]string{}, Cost: -1, } @@ -101,14 +101,15 @@ func TestCsvDataMultiplyFactor(t *testing.T) { ToR: cdrRow[0], OriginHost: "0.0.0.0", Source: "TEST_CDRC", - Usage: time.Duration(1024) * time.Second, + Usage: time.Duration(1024), ExtraFields: map[string]string{}, Cost: -1, } - if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) { + if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, + cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) { t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr) } - cdrRow = []string{"*voice", "1"} + cdrRow = []string{"*voice", "1s"} expectedCdr = &engine.CDR{ CGRID: utils.Sha1("", sTime.String()), ToR: cdrRow[0], @@ -118,17 +119,25 @@ func TestCsvDataMultiplyFactor(t *testing.T) { ExtraFields: map[string]string{}, Cost: -1, } - if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) { + if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, + cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) { t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr) } } func TestCsvPairToRecord(t *testing.T) { - eRecord := []string{"INVITE", "2daec40c", "548625ac", "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", "1436454408", "*prepaid", "1001", "1002", "", "3401:2069362475", "2"} - invPr := &UnpairedRecord{Method: "INVITE", Timestamp: time.Date(2015, 7, 9, 15, 6, 48, 0, time.UTC), - Values: []string{"INVITE", "2daec40c", "548625ac", "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", "1436454408", "*prepaid", "1001", "1002", "", "3401:2069362475"}} + eRecord := []string{"INVITE", "2daec40c", "548625ac", + "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", "1436454408", + "*prepaid", "1001", "1002", "", "3401:2069362475", "2"} + invPr := &UnpairedRecord{Method: "INVITE", + Timestamp: time.Date(2015, 7, 9, 15, 6, 48, 0, time.UTC), + Values: []string{"INVITE", "2daec40c", "548625ac", + "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", + "1436454408", "*prepaid", "1001", "1002", "", "3401:2069362475"}} byePr := &UnpairedRecord{Method: "BYE", Timestamp: time.Date(2015, 7, 9, 15, 6, 50, 0, time.UTC), - Values: []string{"BYE", "2daec40c", "548625ac", "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", "1436454410", "", "", "", "", "3401:2069362475"}} + Values: []string{"BYE", "2daec40c", "548625ac", + "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", + "1436454410", "", "", "", "", "3401:2069362475"}} if rec, err := pairToRecord(invPr, byePr); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRecord, rec) { @@ -145,7 +154,9 @@ func TestCsvPairToRecord(t *testing.T) { if _, err := pairToRecord(invPr, invPr); err == nil || err.Error() != "MISSING_BYE" { t.Error(err) } - byePr.Values = []string{"BYE", "2daec40c", "548625ac", "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", "1436454410", "", "", "", "3401:2069362475"} // Took one value out + byePr.Values = []string{"BYE", "2daec40c", "548625ac", + "dd0c4c617a9919d29a6175cdff223a9e@0:0:0:0:0:0:0:0", "200", "OK", + "1436454410", "", "", "", "3401:2069362475"} // Took one value out if _, err := pairToRecord(invPr, byePr); err == nil || err.Error() != "INCONSISTENT_VALUES_LENGTH" { t.Error(err) } diff --git a/cdrc/xml.go b/cdrc/xml.go index 3ffbbbeda..31380dc23 100644 --- a/cdrc/xml.go +++ b/cdrc/xml.go @@ -91,7 +91,8 @@ func handlerSubstractUsage(xmlElmnt tree.Res, argsTpl utils.RSRFields, cdrPath u return tEnd.Sub(tStart), nil } -func NewXMLRecordsProcessor(recordsReader io.Reader, cdrPath utils.HierarchyPath, timezone string, httpSkipTlsCheck bool, cdrcCfgs []*config.CdrcConfig) (*XMLRecordsProcessor, error) { +func NewXMLRecordsProcessor(recordsReader io.Reader, cdrPath utils.HierarchyPath, timezone string, + httpSkipTlsCheck bool, cdrcCfgs []*config.CdrcConfig) (*XMLRecordsProcessor, error) { xp, err := goxpath.Parse(cdrPath.AsString("/", true)) if err != nil { return nil, err @@ -103,7 +104,8 @@ func NewXMLRecordsProcessor(recordsReader io.Reader, cdrPath utils.HierarchyPath if err != nil { return nil, err } - xmlProc := &XMLRecordsProcessor{cdrPath: cdrPath, timezone: timezone, httpSkipTlsCheck: httpSkipTlsCheck, cdrcCfgs: cdrcCfgs} + xmlProc := &XMLRecordsProcessor{cdrPath: cdrPath, timezone: timezone, + httpSkipTlsCheck: httpSkipTlsCheck, cdrcCfgs: cdrcCfgs} xmlProc.cdrXmlElmts = goxpath.MustExec(xp, xmlNode, nil) return xmlProc, nil } @@ -161,19 +163,19 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con cdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var lazyHttpFields []*config.CfgCdrField var err error + fldVals := make(map[string]string) for _, cdrFldCfg := range cdrcCfg.ContentFields { - var fieldVal string if cdrFldCfg.Type == utils.META_COMPOSED { for _, cfgFieldRSR := range cdrFldCfg.Value { if cfgFieldRSR.IsStatic() { - fieldVal += cfgFieldRSR.ParseValue("") + fldVals[cdrFldCfg.FieldId] += cfgFieldRSR.ParseValue("") } else { // Dynamic value extracted using path absolutePath := utils.ParseHierarchyPath(cfgFieldRSR.Id, "") relPath := utils.HierarchyPath(absolutePath[len(xmlProc.cdrPath)-1:]) // Need relative path to the xmlElmnt if elmntText, err := elementText(xmlEntity, relPath.AsString("/", true)); err != nil && err != utils.ErrNotFound { return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error()) } else { - fieldVal += cfgFieldRSR.ParseValue(elmntText) + fldVals[cdrFldCfg.FieldId] += cfgFieldRSR.ParseValue(elmntText) } } } @@ -184,11 +186,11 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity tree.Res, cdrcCfg *con if err != nil { return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s, err: %s", xmlEntity, cdrFldCfg.Tag, err.Error()) } - fieldVal += strconv.FormatFloat(usage.Seconds(), 'f', -1, 64) + fldVals[cdrFldCfg.FieldId] += strconv.FormatFloat(usage.Seconds(), 'f', -1, 64) } else { return nil, fmt.Errorf("Unsupported field type: %s", cdrFldCfg.Type) } - if err := cdr.ParseFieldValue(cdrFldCfg.FieldId, fieldVal, xmlProc.timezone); err != nil { + if err := cdr.ParseFieldValue(cdrFldCfg.FieldId, fldVals[cdrFldCfg.FieldId], xmlProc.timezone); err != nil { return nil, err } } diff --git a/cdrc/xml_test.go b/cdrc/xml_test.go index 414fe7e49..da245fb69 100644 --- a/cdrc/xml_test.go +++ b/cdrc/xml_test.go @@ -233,8 +233,12 @@ func TestXMLRPProcess(t *testing.T) { Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>startTime", utils.INFIELD_SEP), Mandatory: true}, &config.CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>answerTime", utils.INFIELD_SEP), Mandatory: true}, - &config.CfgCdrField{Tag: "Usage", Type: utils.META_HANDLER, FieldId: utils.USAGE, HandlerId: utils.HandlerSubstractUsage, - Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime", utils.INFIELD_SEP), Mandatory: true}, + &config.CfgCdrField{Tag: "Usage", Type: utils.META_HANDLER, + FieldId: utils.USAGE, HandlerId: utils.HandlerSubstractUsage, + Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>releaseTime;^|;broadWorksCDR>cdrData>basicModule>answerTime", + utils.INFIELD_SEP), Mandatory: true}, + &config.CfgCdrField{Tag: "UsageSeconds", Type: utils.META_COMPOSED, FieldId: utils.USAGE, + Value: utils.ParseRSRFieldsMustCompile("^s", utils.INFIELD_SEP), Mandatory: true}, }, }, } diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index d2ccb7981..9e714a964 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -725,7 +725,7 @@ func main() { defer pprof.StopCPUProfile() } if *scheduledShutdown != "" { - shutdownDur, err := utils.ParseDurationWithSecs(*scheduledShutdown) + shutdownDur, err := utils.ParseDurationWithNanosecs(*scheduledShutdown) if err != nil { log.Fatal(err) } diff --git a/cmd/cgr-tester/cgr-tester.go b/cmd/cgr-tester/cgr-tester.go index 30dbb0acd..1e39f12ed 100644 --- a/cmd/cgr-tester/cgr-tester.go +++ b/cmd/cgr-tester/cgr-tester.go @@ -156,7 +156,7 @@ func main() { var timeparsed time.Duration var err error tstart := time.Now().Local() - timeparsed, err = utils.ParseDurationWithSecs(*usage) + timeparsed, err = utils.ParseDurationWithNanosecs(*usage) tend := tstart.Add(timeparsed) cd := &engine.CallDescriptor{ TimeStart: tstart, diff --git a/config/cacheconfig.go b/config/cacheconfig.go index bbc8bc4e4..d31366a2c 100755 --- a/config/cacheconfig.go +++ b/config/cacheconfig.go @@ -40,7 +40,7 @@ func (self *CacheParamConfig) loadFromJsonCfg(jsnCfg *CacheParamJsonCfg) error { self.Limit = *jsnCfg.Limit } if jsnCfg.Ttl != nil { - if self.TTL, err = utils.ParseDurationWithSecs(*jsnCfg.Ttl); err != nil { + if self.TTL, err = utils.ParseDurationWithNanosecs(*jsnCfg.Ttl); err != nil { return err } } diff --git a/config/cdrcconfig.go b/config/cdrcconfig.go index bfb5db4f7..f9d8326fb 100644 --- a/config/cdrcconfig.go +++ b/config/cdrcconfig.go @@ -114,7 +114,7 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error { self.ContinueOnSuccess = *jsnCfg.Continue_on_success } if jsnCfg.Partial_record_cache != nil { - if self.PartialRecordCache, err = utils.ParseDurationWithSecs(*jsnCfg.Partial_record_cache); err != nil { + if self.PartialRecordCache, err = utils.ParseDurationWithNanosecs(*jsnCfg.Partial_record_cache); err != nil { return err } } diff --git a/config/config.go b/config/config.go index 4038d6b33..72788f5f0 100755 --- a/config/config.go +++ b/config/config.go @@ -772,7 +772,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { self.ConnectAttempts = *jsnGeneralCfg.Connect_attempts } if jsnGeneralCfg.Response_cache_ttl != nil { - if self.ResponseCacheTTL, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Response_cache_ttl); err != nil { + if self.ResponseCacheTTL, err = utils.ParseDurationWithNanosecs(*jsnGeneralCfg.Response_cache_ttl); err != nil { return err } } @@ -780,12 +780,12 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { self.Reconnects = *jsnGeneralCfg.Reconnects } if jsnGeneralCfg.Connect_timeout != nil { - if self.ConnectTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Connect_timeout); err != nil { + if self.ConnectTimeout, err = utils.ParseDurationWithNanosecs(*jsnGeneralCfg.Connect_timeout); err != nil { return err } } if jsnGeneralCfg.Reply_timeout != nil { - if self.ReplyTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Reply_timeout); err != nil { + if self.ReplyTimeout, err = utils.ParseDurationWithNanosecs(*jsnGeneralCfg.Reply_timeout); err != nil { return err } } @@ -808,12 +808,12 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { self.DefaultTimezone = *jsnGeneralCfg.Default_timezone } if jsnGeneralCfg.Internal_ttl != nil { - if self.InternalTtl, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Internal_ttl); err != nil { + if self.InternalTtl, err = utils.ParseDurationWithNanosecs(*jsnGeneralCfg.Internal_ttl); err != nil { return err } } if jsnGeneralCfg.Locking_timeout != nil { - if self.LockingTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Locking_timeout); err != nil { + if self.LockingTimeout, err = utils.ParseDurationWithNanosecs(*jsnGeneralCfg.Locking_timeout); err != nil { return err } } @@ -999,7 +999,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnCdrstatsCfg.Enabled != nil { self.CDRStatsEnabled = *jsnCdrstatsCfg.Enabled if jsnCdrstatsCfg.Save_Interval != nil { - if self.CDRStatsSaveInterval, err = utils.ParseDurationWithSecs(*jsnCdrstatsCfg.Save_Interval); err != nil { + if self.CDRStatsSaveInterval, err = utils.ParseDurationWithNanosecs(*jsnCdrstatsCfg.Save_Interval); err != nil { return err } } @@ -1116,7 +1116,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { self.HistoryDir = *jsnHistServCfg.History_dir } if jsnHistServCfg.Save_interval != nil { - if self.HistorySaveInterval, err = utils.ParseDurationWithSecs(*jsnHistServCfg.Save_interval); err != nil { + if self.HistorySaveInterval, err = utils.ParseDurationWithNanosecs(*jsnHistServCfg.Save_interval); err != nil { return err } } diff --git a/config/daconfig.go b/config/daconfig.go index 18a1e765a..92b8d2e88 100644 --- a/config/daconfig.go +++ b/config/daconfig.go @@ -76,7 +76,7 @@ func (self *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg) erro } if jsnCfg.Debit_interval != nil { var err error - if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil { + if self.DebitInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Debit_interval); err != nil { return err } } diff --git a/config/reslimitercfg.go b/config/reslimitercfg.go index 09b988903..3ed767136 100644 --- a/config/reslimitercfg.go +++ b/config/reslimitercfg.go @@ -46,7 +46,7 @@ func (rlcfg *ResourceSConfig) loadFromJsonCfg(jsnCfg *ResourceSJsonCfg) (err err } } if jsnCfg.Store_interval != nil { - if rlcfg.StoreInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Store_interval); err != nil { + if rlcfg.StoreInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Store_interval); err != nil { return } } diff --git a/config/smconfig.go b/config/smconfig.go index a3ab87d76..af7d29527 100644 --- a/config/smconfig.go +++ b/config/smconfig.go @@ -137,34 +137,34 @@ func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error { } } if jsnCfg.Debit_interval != nil { - if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil { + if self.DebitInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Debit_interval); err != nil { return err } } if jsnCfg.Min_call_duration != nil { - if self.MinCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Min_call_duration); err != nil { + if self.MinCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Min_call_duration); err != nil { return err } } if jsnCfg.Max_call_duration != nil { - if self.MaxCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Max_call_duration); err != nil { + if self.MaxCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_call_duration); err != nil { return err } } if jsnCfg.Session_ttl != nil { - if self.SessionTTL, err = utils.ParseDurationWithSecs(*jsnCfg.Session_ttl); err != nil { + if self.SessionTTL, err = utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl); err != nil { return err } } if jsnCfg.Session_ttl_max_delay != nil { - if maxTTLDelay, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_max_delay); err != nil { + if maxTTLDelay, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_max_delay); err != nil { return err } else { self.SessionTTLMaxDelay = &maxTTLDelay } } if jsnCfg.Session_ttl_last_used != nil { - if sessionTTLLastUsed, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_last_used); err != nil { + if sessionTTLLastUsed, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_last_used); err != nil { return err } else { self.SessionTTLLastUsed = &sessionTTLLastUsed @@ -234,22 +234,22 @@ func (self *SmFsConfig) loadFromJsonCfg(jsnCfg *SmFsJsonCfg) error { } } if jsnCfg.Debit_interval != nil { - if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil { + if self.DebitInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Debit_interval); err != nil { return err } } if jsnCfg.Min_call_duration != nil { - if self.MinCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Min_call_duration); err != nil { + if self.MinCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Min_call_duration); err != nil { return err } } if jsnCfg.Max_call_duration != nil { - if self.MaxCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Max_call_duration); err != nil { + if self.MaxCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_call_duration); err != nil { return err } } if jsnCfg.Min_dur_low_balance != nil { - if self.MinDurLowBalance, err = utils.ParseDurationWithSecs(*jsnCfg.Min_dur_low_balance); err != nil { + if self.MinDurLowBalance, err = utils.ParseDurationWithNanosecs(*jsnCfg.Min_dur_low_balance); err != nil { return err } } @@ -266,12 +266,12 @@ func (self *SmFsConfig) loadFromJsonCfg(jsnCfg *SmFsJsonCfg) error { self.SubscribePark = *jsnCfg.Subscribe_park } if jsnCfg.Channel_sync_interval != nil { - if self.ChannelSyncInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Channel_sync_interval); err != nil { + if self.ChannelSyncInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Channel_sync_interval); err != nil { return err } } if jsnCfg.Max_wait_connection != nil { - if self.MaxWaitConnection, err = utils.ParseDurationWithSecs(*jsnCfg.Max_wait_connection); err != nil { + if self.MaxWaitConnection, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_wait_connection); err != nil { return err } } @@ -359,17 +359,17 @@ func (self *SmKamConfig) loadFromJsonCfg(jsnCfg *SmKamJsonCfg) error { self.CreateCdr = *jsnCfg.Create_cdr } if jsnCfg.Debit_interval != nil { - if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil { + if self.DebitInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Debit_interval); err != nil { return err } } if jsnCfg.Min_call_duration != nil { - if self.MinCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Min_call_duration); err != nil { + if self.MinCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Min_call_duration); err != nil { return err } } if jsnCfg.Max_call_duration != nil { - if self.MaxCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Max_call_duration); err != nil { + if self.MaxCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_call_duration); err != nil { return err } } @@ -439,22 +439,22 @@ func (self *SmOsipsConfig) loadFromJsonCfg(jsnCfg *SmOsipsJsonCfg) error { self.CreateCdr = *jsnCfg.Create_cdr } if jsnCfg.Debit_interval != nil { - if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil { + if self.DebitInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Debit_interval); err != nil { return err } } if jsnCfg.Min_call_duration != nil { - if self.MinCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Min_call_duration); err != nil { + if self.MinCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Min_call_duration); err != nil { return err } } if jsnCfg.Max_call_duration != nil { - if self.MaxCallDuration, err = utils.ParseDurationWithSecs(*jsnCfg.Max_call_duration); err != nil { + if self.MaxCallDuration, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_call_duration); err != nil { return err } } if jsnCfg.Events_subscribe_interval != nil { - if self.EventsSubscribeInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Events_subscribe_interval); err != nil { + if self.EventsSubscribeInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Events_subscribe_interval); err != nil { return err } } diff --git a/config/statscfg.go b/config/statscfg.go index 4c078188b..2863d0967 100644 --- a/config/statscfg.go +++ b/config/statscfg.go @@ -39,7 +39,7 @@ func (st *StatSCfg) loadFromJsonCfg(jsnCfg *StatServJsonCfg) (err error) { st.Enabled = *jsnCfg.Enabled } if jsnCfg.Store_interval != nil { - if st.StoreInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Store_interval); err != nil { + if st.StoreInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Store_interval); err != nil { return err } } diff --git a/config/thresholdscfg.go b/config/thresholdscfg.go index 625dd2bcc..257d7b9e0 100644 --- a/config/thresholdscfg.go +++ b/config/thresholdscfg.go @@ -38,7 +38,7 @@ func (t *ThresholdSCfg) loadFromJsonCfg(jsnCfg *ThresholdSJsonCfg) (err error) { t.Enabled = *jsnCfg.Enabled } if jsnCfg.Store_interval != nil { - if t.StoreInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Store_interval); err != nil { + if t.StoreInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Store_interval); err != nil { return err } } diff --git a/engine/action.go b/engine/action.go index e6eec5205..8ed9cdaaa 100644 --- a/engine/action.go +++ b/engine/action.go @@ -216,7 +216,9 @@ func cdrLogAction(acc *Account, sq *CDRStatsQueueTriggered, a *Action, acs Actio if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET, TOPUP, TOPUP_RESET}, action.ActionType) || action.Balance == nil { continue // Only log specific actions } - cdr := &CDR{RunID: action.ActionType, Source: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), OriginID: utils.GenUUID(), ExtraFields: make(map[string]string)} + cdr := &CDR{RunID: action.ActionType, Source: CDRLOG, + SetupTime: time.Now(), AnswerTime: time.Now(), OriginID: utils.GenUUID(), + ExtraFields: make(map[string]string)} cdr.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.String()) cdr.Usage = time.Duration(1) * time.Second elem := reflect.ValueOf(cdr).Elem() diff --git a/engine/cdr.go b/engine/cdr.go index 241212fe7..243ae8046 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -51,7 +51,7 @@ func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { } } if extCdr.Usage != "" { - if cdr.Usage, err = utils.ParseDurationWithSecs(extCdr.Usage); err != nil { + if cdr.Usage, err = utils.ParseDurationWithNanosecs(extCdr.Usage); err != nil { return nil, err } } @@ -175,7 +175,7 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { case utils.ANSWER_TIME: return rsrFld.ParseValue(cdr.AnswerTime.Format(time.RFC3339)) case utils.USAGE: - return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) + return cdr.Usage.String() case utils.MEDI_RUNID: return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: @@ -228,7 +228,7 @@ func (cdr *CDR) ParseFieldValue(fieldId, fieldVal, timezone string) error { return fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) } case utils.USAGE: - if cdr.Usage, err = utils.ParseDurationWithSecs(fieldVal); err != nil { + if cdr.Usage, err = utils.ParseDurationWithNanosecs(fieldVal); err != nil { return fmt.Errorf("Cannot parse duration field with value: %s, err: %s", fieldVal, err.Error()) } case utils.COST: @@ -380,7 +380,7 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, tenantFld, categFld, accou durStr := cdr.FieldAsString(durationFld) if primaryMandatory && len(durStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.USAGE, durationFld.Id) - } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { + } else if frkStorCdr.Usage, err = utils.ParseDurationWithNanosecs(durStr); err != nil { return nil, err } ratedStr := cdr.FieldAsString(ratedFld) @@ -547,7 +547,7 @@ func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { } else { durVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } - return utils.ParseDurationWithSecs(durVal) + return utils.ParseDurationWithNanosecs(durVal) } func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { @@ -870,7 +870,7 @@ func (self *UsageRecord) AsStoredCdr(timezone string) (*CDR, error) { if cdr.AnswerTime, err = utils.ParseTimeDetectLayout(self.AnswerTime, timezone); err != nil { return nil, err } - if cdr.Usage, err = utils.ParseDurationWithSecs(self.Usage); err != nil { + if cdr.Usage, err = utils.ParseDurationWithNanosecs(self.Usage); err != nil { return nil, err } if self.ExtraFields != nil { @@ -902,7 +902,7 @@ func (self *UsageRecord) AsCallDescriptor(timezone string, denyNegative bool) (* if cd.TimeStart, err = utils.ParseTimeDetectLayout(timeStr, timezone); err != nil { return nil, err } - if usage, err := utils.ParseDurationWithSecs(self.Usage); err != nil { + if usage, err := utils.ParseDurationWithNanosecs(self.Usage); err != nil { return nil, err } else { cd.TimeEnd = cd.TimeStart.Add(usage) diff --git a/engine/cdr_test.go b/engine/cdr_test.go index b96ee41b8..4c8d6ccad 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -39,7 +39,7 @@ func TestNewCDRFromExternalCDR(t *testing.T) { Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.DEFAULT_RUNID, - Usage: "0.00000001", Cost: 1.01, Rated: true, + Usage: "10", Cost: 1.01, Rated: true, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } eStorCdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -98,7 +98,7 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination || cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339) || cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339) || - cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" || + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s" || cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.RunID || cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01" || cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"] || @@ -118,7 +118,7 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination, cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339), cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339), - cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10", + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s", cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.RunID, cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01", cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"], @@ -497,9 +497,9 @@ func TestUsageReqAsCD(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", - Usage: "0.00000001", + Usage: "10", } - eCD := &CallDescriptor{CgrID: "48ca1a2eb82b028fbfc809e36a585061a775ffc3", TOR: req.ToR, + eCD := &CallDescriptor{CgrID: "c4630df20b2a0c5b11311e4b5a8c3178cf314344", TOR: req.ToR, Direction: utils.OUT, Tenant: req.Tenant, Category: req.Category, Account: req.Account, Subject: req.Subject, Destination: req.Destination, diff --git a/engine/cgrcdr.go b/engine/cgrcdr.go index de3cbe296..578a20a54 100644 --- a/engine/cgrcdr.go +++ b/engine/cgrcdr.go @@ -73,7 +73,7 @@ func (cgrCdr CgrCdr) AsStoredCdr(timezone string) *CDR { storCdr.Destination = cgrCdr[utils.DESTINATION] storCdr.SetupTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], timezone) // Not interested to process errors, should do them if necessary in a previous step storCdr.AnswerTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.ANSWER_TIME], timezone) - storCdr.Usage, _ = utils.ParseDurationWithSecs(cgrCdr[utils.USAGE]) + storCdr.Usage, _ = utils.ParseDurationWithNanosecs(cgrCdr[utils.USAGE]) storCdr.ExtraFields = cgrCdr.getExtraFields() storCdr.Cost = -1 if costStr, hasIt := cgrCdr[utils.COST]; hasIt { diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index b020ca2e8..8a7b8d963 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -38,7 +38,7 @@ func TestCgrCdrAsCDR(t *testing.T) { utils.TENANT: "cgrates.org", utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-07T08:42:20Z", utils.ANSWER_TIME: "2013-11-07T08:42:26Z", - utils.USAGE: "10", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} + utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], @@ -63,7 +63,7 @@ func TestReplicatedCgrCdrAsCDR(t *testing.T) { utils.CDRSOURCE: "internal_test", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: utils.OUT, utils.TENANT: "cgrates.org", utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-07T08:42:20Z", utils.PDD: "0.200", utils.ANSWER_TIME: "2013-11-07T08:42:26Z", - utils.USAGE: "10", utils.SUPPLIER: "SUPPL1", utils.DISCONNECT_CAUSE: "NORMAL_CLEARING", utils.COST: "0.12", utils.RATED: "true", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} + utils.USAGE: "10s", utils.SUPPLIER: "SUPPL1", utils.DISCONNECT_CAUSE: "NORMAL_CLEARING", utils.COST: "0.12", utils.RATED: "true", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} expctRtCdr := &CDR{CGRID: cgrCdr[utils.CGRID], ToR: cgrCdr[utils.TOR], OriginID: cgrCdr[utils.ACCID], diff --git a/engine/lcr.go b/engine/lcr.go index 2556ef083..fbfa8838a 100644 --- a/engine/lcr.go +++ b/engine/lcr.go @@ -93,7 +93,7 @@ func (self *LcrRequest) AsCallDescriptor(timezone string) (*CallDescriptor, erro var callDur time.Duration if len(self.Duration) == 0 { callDur = time.Duration(1) * time.Minute - } else if callDur, err = utils.ParseDurationWithSecs(self.Duration); err != nil { + } else if callDur, err = utils.ParseDurationWithNanosecs(self.Duration); err != nil { return nil, err } cd := &CallDescriptor{ @@ -198,22 +198,22 @@ func (le *LCREntry) GetQOSLimits() (minASR, maxASR float64, minPDD, maxPDD, minA if maxASR, err = strconv.ParseFloat(params[1], 64); err != nil { maxASR = -1 } - if minPDD, err = utils.ParseDurationWithSecs(params[2]); err != nil || params[2] == "" { + if minPDD, err = utils.ParseDurationWithNanosecs(params[2]); err != nil || params[2] == "" { minPDD = -1 } - if maxPDD, err = utils.ParseDurationWithSecs(params[3]); err != nil || params[3] == "" { + if maxPDD, err = utils.ParseDurationWithNanosecs(params[3]); err != nil || params[3] == "" { maxPDD = -1 } - if minACD, err = utils.ParseDurationWithSecs(params[4]); err != nil || params[4] == "" { + if minACD, err = utils.ParseDurationWithNanosecs(params[4]); err != nil || params[4] == "" { minACD = -1 } - if maxACD, err = utils.ParseDurationWithSecs(params[5]); err != nil || params[5] == "" { + if maxACD, err = utils.ParseDurationWithNanosecs(params[5]); err != nil || params[5] == "" { maxACD = -1 } - if minTCD, err = utils.ParseDurationWithSecs(params[6]); err != nil || params[6] == "" { + if minTCD, err = utils.ParseDurationWithNanosecs(params[6]); err != nil || params[6] == "" { minTCD = -1 } - if maxTCD, err = utils.ParseDurationWithSecs(params[7]); err != nil || params[7] == "" { + if maxTCD, err = utils.ParseDurationWithNanosecs(params[7]); err != nil || params[7] == "" { maxTCD = -1 } if minACC, err = strconv.ParseFloat(params[8], 64); err != nil { diff --git a/engine/lcr_test.go b/engine/lcr_test.go index b28f99752..6ea9916b7 100644 --- a/engine/lcr_test.go +++ b/engine/lcr_test.go @@ -93,7 +93,7 @@ func TestLcrQOSSorterOACD(t *testing.T) { func TestLcrGetQosLimitsAll(t *testing.T) { le := &LCREntry{ - StrategyParams: "1.2;2.3;4;7;45s;67m;16s;17m;8.9;10.11;12.13;14.15;2;3", + StrategyParams: "1.2;2.3;4s;7s;45s;67m;16s;17m;8.9;10.11;12.13;14.15;2;3", } minAsr, maxAsr, minPdd, maxPdd, minAcd, maxAcd, minTcd, maxTcd, minAcc, maxAcc, minTcc, maxTcc, minDdc, maxDdc := le.GetQOSLimits() if minAsr != 1.2 || maxAsr != 2.3 || @@ -109,7 +109,7 @@ func TestLcrGetQosLimitsAll(t *testing.T) { func TestLcrGetQosLimitsSome(t *testing.T) { le := &LCREntry{ - StrategyParams: "1.2;;3;;;67m;;30m;1;;3;;;2", + StrategyParams: "1.2;;3s;;;67m;;30m;1;;3;;;2", } minAsr, maxAsr, minPdd, maxPdd, minAcd, maxAcd, minTcd, maxTcd, minAcc, maxAcc, minTcc, maxTcc, minDdc, maxDdc := le.GetQOSLimits() if minAsr != 1.2 || maxAsr != -1 || diff --git a/engine/libstats.go b/engine/libstats.go index 8a94e5b9a..d7478eca2 100755 --- a/engine/libstats.go +++ b/engine/libstats.go @@ -91,7 +91,7 @@ func (se StatEvent) Usage() (at time.Duration, err error) { if !canCast { return at, errors.New("cannot cast to string") } - return utils.ParseDurationWithSecs(usStr) + return utils.ParseDurationWithNanosecs(usStr) } // Cost returns the Cost of StatEvent @@ -126,7 +126,7 @@ func (se StatEvent) Pdd() (pdd time.Duration, err error) { if !canCast { return pdd, errors.New("cannot cast to string") } - return utils.ParseDurationWithSecs(pddStr) + return utils.ParseDurationWithNanosecs(pddStr) } // Destination returns the Destination of StatEvent diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index e0f0e924a..069307102 100755 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -58,20 +58,20 @@ WEEKENDS,*any,*any,*any,6;7,00:00:00 ONE_TIME_RUN,2012,,,,*asap ` rates = ` -R1,0,0.2,60,1,0 -R2,0,0.1,60s,1s,0 -R3,0,0.05,60s,1s,0 -R4,1,1,1s,1s,0 -R5,0,0.5,1s,1s,0 -LANDLINE_OFFPEAK,0,1,1,60,0 -LANDLINE_OFFPEAK,0,1,1,1,60 +R1,0,0.2,60s,1s,0s +R2,0,0.1,60s,1s,0s +R3,0,0.05,60s,1s,0s +R4,1,1,1s,1s,0s +R5,0,0.5,1s,1s,0s +LANDLINE_OFFPEAK,0,1,1s,60s,0s +LANDLINE_OFFPEAK,0,1,1s,1s,60s GBP_71,0.000000,5.55555,1s,1s,0s GBP_72,0.000000,7.77777,1s,1s,0s -GBP_70,0.000000,1,1,1,0 +GBP_70,0.000000,1,1,1s,0s RT_UK_Mobile_BIG5_PKG,0.01,0,20s,20s,0s RT_UK_Mobile_BIG5,0.01,0.10,1s,1s,0s -R_URG,0,0,1,1,0 -MX,0,1,1s,1s,0 +R_URG,0,0,1s,1s,0s +MX,0,1,1s,1s,0s DY,0.15,0.05,60s,1s,0s CF,1.12,0,1s,1s,0s ` @@ -488,7 +488,7 @@ func TestLoadRates(t *testing.T) { t.Error("Failed to load rates: ", len(csvr.rates)) } rate := csvr.rates["R1"].RateSlots[0] - expctRs, err := utils.NewRateSlot(0, 0.2, "60", "1", "0") + expctRs, err := utils.NewRateSlot(0, 0.2, "60s", "1s", "0s") if err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || @@ -498,16 +498,16 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", rate, expctRs) } rate = csvr.rates["R2"].RateSlots[0] - if expctRs, err = utils.NewRateSlot(0, 0.1, "60s", "1s", "0"); err != nil { + if expctRs, err = utils.NewRateSlot(0, 0.1, "60s", "1s", "0s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || rate.RateIncrementDuration() != expctRs.RateIncrementDuration() || rate.GroupIntervalStartDuration() != expctRs.GroupIntervalStartDuration() { - t.Error("Error loading rate: ", rate) + t.Errorf("Expecting: %+v, received: %+v", expctRs, rate) } rate = csvr.rates["R3"].RateSlots[0] - if expctRs, err = utils.NewRateSlot(0, 0.05, "60s", "1s", "0"); err != nil { + if expctRs, err = utils.NewRateSlot(0, 0.05, "60s", "1s", "0s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || @@ -516,7 +516,7 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", rate) } rate = csvr.rates["R4"].RateSlots[0] - if expctRs, err = utils.NewRateSlot(1, 1.0, "1s", "1s", "0"); err != nil { + if expctRs, err = utils.NewRateSlot(1, 1.0, "1s", "1s", "0s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || @@ -525,7 +525,7 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", rate) } rate = csvr.rates["R5"].RateSlots[0] - if expctRs, err = utils.NewRateSlot(0, 0.5, "1s", "1s", "0"); err != nil { + if expctRs, err = utils.NewRateSlot(0, 0.5, "1s", "1s", "0s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || @@ -534,7 +534,7 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", rate) } rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[0] - if expctRs, err = utils.NewRateSlot(0, 1, "1", "60", "0"); err != nil { + if expctRs, err = utils.NewRateSlot(0, 1, "1s", "60s", "0s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || @@ -543,7 +543,7 @@ func TestLoadRates(t *testing.T) { t.Error("Error loading rate: ", rate) } rate = csvr.rates["LANDLINE_OFFPEAK"].RateSlots[1] - if expctRs, err = utils.NewRateSlot(0, 1, "1", "1", "60"); err != nil { + if expctRs, err = utils.NewRateSlot(0, 1, "1s", "1s", "60s"); err != nil { t.Error("Error loading rate: ", rate, err.Error()) } else if !reflect.DeepEqual(rate, expctRs) || rate.RateUnitDuration() != expctRs.RateUnitDuration() || diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 7b760ec11..8d984a078 100755 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -1925,7 +1925,7 @@ func APItoResource(tpRL *utils.TPResource, timezone string) (rp *ResourceProfile AllocationMessage: tpRL.AllocationMessage, } if tpRL.UsageTTL != "" { - if rp.UsageTTL, err = utils.ParseDurationWithSecs(tpRL.UsageTTL); err != nil { + if rp.UsageTTL, err = utils.ParseDurationWithNanosecs(tpRL.UsageTTL); err != nil { return nil, err } } @@ -2077,7 +2077,7 @@ func APItoStats(tpST *utils.TPStats, timezone string) (st *StatQueueProfile, err MinItems: tpST.MinItems, } if tpST.TTL != "" { - if st.TTL, err = utils.ParseDurationWithSecs(tpST.TTL); err != nil { + if st.TTL, err = utils.ParseDurationWithNanosecs(tpST.TTL); err != nil { return nil, err } } @@ -2282,7 +2282,7 @@ func APItoThresholdProfile(tpTH *utils.TPThreshold, timezone string) (th *Thresh Async: tpTH.Async, } if tpTH.MinSleep != "" { - if th.MinSleep, err = utils.ParseDurationWithSecs(tpTH.MinSleep); err != nil { + if th.MinSleep, err = utils.ParseDurationWithNanosecs(tpTH.MinSleep); err != nil { return nil, err } } diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 295da0f1e..aa21f8797 100755 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -875,7 +875,7 @@ func TestAPItoTPStats(t *testing.T) { Weight: 20.0, MinItems: tps.MinItems, } - if eTPs.TTL, err = utils.ParseDurationWithSecs(tps.TTL); err != nil { + if eTPs.TTL, err = utils.ParseDurationWithNanosecs(tps.TTL); err != nil { t.Errorf("Got error: %+v", err) } at, _ := utils.ParseTimeDetectLayout("2014-07-29T15:00:00Z", "UTC") @@ -948,7 +948,7 @@ func TestAPItoTPThreshold(t *testing.T) { FilterIDs: tps.FilterIDs, ActionIDs: []string{"WARN3"}, } - if eTPs.MinSleep, err = utils.ParseDurationWithSecs(tps.MinSleep); err != nil { + if eTPs.MinSleep, err = utils.ParseDurationWithNanosecs(tps.MinSleep); err != nil { t.Errorf("Got error: %+v", err) } at, _ := utils.ParseTimeDetectLayout("2014-07-29T15:00:00Z", "UTC") diff --git a/engine/responder.go b/engine/responder.go index c67ee312e..bfb9d1de5 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -535,7 +535,7 @@ func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error { func (rs *Responder) Status(arg string, reply *map[string]interface{}) (err error) { if arg != "" { // Introduce delay in answer, used in some automated tests - if delay, err := utils.ParseDurationWithSecs(arg); err == nil { + if delay, err := utils.ParseDurationWithNanosecs(arg); err == nil { time.Sleep(delay) } } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index c8bf5bf38..3169e154a 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -984,28 +984,28 @@ func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, int64, error) { var minPDD, maxPDD, minUsage, maxUsage *time.Duration if len(qryFltr.MinPDD) != 0 { - if parsed, err := utils.ParseDurationWithSecs(qryFltr.MinPDD); err != nil { + if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { return nil, 0, err } else { minPDD = &parsed } } if len(qryFltr.MaxPDD) != 0 { - if parsed, err := utils.ParseDurationWithSecs(qryFltr.MaxPDD); err != nil { + if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { return nil, 0, err } else { maxPDD = &parsed } } if len(qryFltr.MinUsage) != 0 { - if parsed, err := utils.ParseDurationWithSecs(qryFltr.MinUsage); err != nil { + if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MinUsage); err != nil { return nil, 0, err } else { minUsage = &parsed } } if len(qryFltr.MaxUsage) != 0 { - if parsed, err := utils.ParseDurationWithSecs(qryFltr.MaxUsage); err != nil { + if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MaxUsage); err != nil { return nil, 0, err } else { maxUsage = &parsed diff --git a/engine/tp_reader.go b/engine/tp_reader.go index e445154b8..4ac0f1ab2 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -733,7 +733,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) { if err != nil { return err } - minSleep, err := utils.ParseDurationWithSecs(atr.MinSleep) + minSleep, err := utils.ParseDurationWithNanosecs(atr.MinSleep) if err != nil { return err } @@ -932,7 +932,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) for key, atrsLst := range atrs { atrs := make([]*ActionTrigger, len(atrsLst)) for idx, atr := range atrsLst { - minSleep, _ := utils.ParseDurationWithSecs(atr.MinSleep) + minSleep, _ := utils.ParseDurationWithNanosecs(atr.MinSleep) expTime, _ := utils.ParseTimeDetectLayout(atr.ExpirationDate, tpr.timezone) actTime, _ := utils.ParseTimeDetectLayout(atr.ActivationDate, tpr.timezone) if atr.UniqueID == "" { @@ -1266,7 +1266,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { for _, atrsLst := range atrsM { atrs := make([]*ActionTrigger, len(atrsLst)) for idx, atr := range atrsLst { - minSleep, _ := utils.ParseDurationWithSecs(atr.MinSleep) + minSleep, _ := utils.ParseDurationWithNanosecs(atr.MinSleep) expTime, _ := utils.ParseTimeDetectLayout(atr.ExpirationDate, tpr.timezone) actTime, _ := utils.ParseTimeDetectLayout(atr.ActivationDate, tpr.timezone) if atr.UniqueID == "" { diff --git a/general_tests/datachrg1_test.go b/general_tests/datachrg1_test.go index 5f818c7a2..75f32caa3 100644 --- a/general_tests/datachrg1_test.go +++ b/general_tests/datachrg1_test.go @@ -35,7 +35,7 @@ func TestSetStorageDtChrg1(t *testing.T) { func TestLoadCsvTpDtChrg1(t *testing.T) { timings := `TM1,*any,*any,*any,*any,00:00:00 TM2,*any,*any,*any,*any,01:00:00` - rates := `RT_DATA_2c,0,0.002,10,10,0 + rates := `RT_DATA_2c,0,0.002,10s,10s,0 RT_DATA_1c,0,0.001,10,10,0` destinationRates := `DR_DATA_1,*any,RT_DATA_2c,*up,4,0, DR_DATA_2,*any,RT_DATA_1c,*up,4,0,` @@ -95,7 +95,7 @@ func TestGetDataCostDtChrg1(t *testing.T) { func TestGetDataCostSecondIntDtChrg1(t *testing.T) { usedData := 20 - usageDur := time.Duration(usedData) * time.Second + usageDur := time.Duration(usedData) timeStart := time.Date(2014, 3, 4, 1, 0, 0, 0, time.Local) cd := &engine.CallDescriptor{ Direction: "*out", diff --git a/general_tests/smschrg1_test.go b/general_tests/smschrg1_test.go index 0c0eca418..c0582cfd5 100644 --- a/general_tests/smschrg1_test.go +++ b/general_tests/smschrg1_test.go @@ -70,7 +70,7 @@ func TestSMSLoadCsvTpSmsChrg1(t *testing.T) { } func TestSMSGetDataCostSmsChrg1(t *testing.T) { - usageDur := time.Second + usageDur := time.Duration(1) timeStart := time.Date(2014, 3, 4, 0, 0, 0, 0, time.Local) cd := &engine.CallDescriptor{ Direction: "*out", diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index c2e7dffc5..8d3718d73 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -171,7 +171,7 @@ func (self SMGenericEvent) GetUsage(fieldName string) (time.Duration, error) { return nilDuration, utils.ErrNotFound } result, _ := utils.ConvertIfaceToString(valIf) - return utils.ParseDurationWithSecs(result) + return utils.ParseDurationWithNanosecs(result) } func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) { @@ -183,7 +183,7 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) return nilDuration, utils.ErrNotFound } result, _ := utils.ConvertIfaceToString(valStr) - return utils.ParseDurationWithSecs(result) + return utils.ParseDurationWithNanosecs(result) } // GetSessionTTL retrieves SessionTTL setting out of SMGenericEvent @@ -197,7 +197,7 @@ func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxD return time.Duration(0) } var err error - if sesTTL, err = utils.ParseDurationWithSecs(ttlStr); err != nil { + if sesTTL, err = utils.ParseDurationWithNanosecs(ttlStr); err != nil { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot parse SessionTTL, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) return time.Duration(0) @@ -215,7 +215,7 @@ func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxD self.GetCGRID(utils.META_DEFAULT))) return time.Duration(0) } - if maxTTLDelay, err := utils.ParseDurationWithSecs(maxTTLDelaxStr); err != nil { + if maxTTLDelay, err := utils.ParseDurationWithNanosecs(maxTTLDelaxStr); err != nil { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot parse SessionTTLMaxDelay, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) return time.Duration(0) @@ -240,7 +240,7 @@ func (self SMGenericEvent) GetSessionTTLLastUsed() *time.Duration { if !converted { return nil } - if ttl, err := utils.ParseDurationWithSecs(ttlStr); err != nil { + if ttl, err := utils.ParseDurationWithNanosecs(ttlStr); err != nil { return nil } else { return &ttl @@ -257,7 +257,7 @@ func (self SMGenericEvent) GetSessionTTLUsage() *time.Duration { if !converted { return nil } - if ttl, err := utils.ParseDurationWithSecs(ttlStr); err != nil { + if ttl, err := utils.ParseDurationWithNanosecs(ttlStr); err != nil { return nil } else { return &ttl @@ -273,7 +273,7 @@ func (self SMGenericEvent) GetMaxUsage(fieldName string, cfgMaxUsage time.Durati return cfgMaxUsage, nil } result, _ := utils.ConvertIfaceToString(maxUsageStr) - return utils.ParseDurationWithSecs(result) + return utils.ParseDurationWithNanosecs(result) } func (self SMGenericEvent) GetPdd(fieldName string) (time.Duration, error) { @@ -281,7 +281,7 @@ func (self SMGenericEvent) GetPdd(fieldName string) (time.Duration, error) { fieldName = utils.PDD } result, _ := utils.ConvertIfaceToString(self[fieldName]) - return utils.ParseDurationWithSecs(result) + return utils.ParseDurationWithNanosecs(result) } func (self SMGenericEvent) GetSupplier(fieldName string) string { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 8523b56a6..402201db9 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -116,13 +116,13 @@ type RateSlot struct { // Used to set the durations we need out of strings func (self *RateSlot) SetDurations() error { var err error - if self.rateUnitDur, err = ParseDurationWithSecs(self.RateUnit); err != nil { + if self.rateUnitDur, err = ParseDurationWithNanosecs(self.RateUnit); err != nil { return err } - if self.rateIncrementDur, err = ParseDurationWithSecs(self.RateIncrement); err != nil { + if self.rateIncrementDur, err = ParseDurationWithNanosecs(self.RateIncrement); err != nil { return err } - if self.groupIntervalStartDur, err = ParseDurationWithSecs(self.GroupIntervalStart); err != nil { + if self.groupIntervalStartDur, err = ParseDurationWithNanosecs(self.GroupIntervalStart); err != nil { return err } return nil From 76bc26c726ff3d50f5c3f2e398ca423ee65de6f2 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 31 Oct 2017 20:26:31 +0100 Subject: [PATCH 3/3] RALs max_computed_usage config option --- config/config.go | 9 +++++++++ config/config_defaults.go | 8 +++++++- config/config_json_test.go | 22 +++++++++++++++++----- config/config_test.go | 9 +++++++++ config/libconfig_json.go | 1 + 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index 72788f5f0..2d025ef6d 100755 --- a/config/config.go +++ b/config/config.go @@ -65,6 +65,7 @@ func SetCgrConfig(cfg *CGRConfig) { func NewDefaultCGRConfig() (*CGRConfig, error) { cfg := new(CGRConfig) + cfg.RALsMaxComputedUsage = make(map[string]time.Duration) cfg.InstanceID = utils.GenUUID() cfg.DataFolderPath = "/usr/share/cgrates/" cfg.SmGenericConfig = new(SmGenericConfig) @@ -238,6 +239,7 @@ type CGRConfig struct { RALsAliasSConns []*HaPoolConfig RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject LcrSubjectPrefixMatching bool // enables prefix matching for the lcr subject + RALsMaxComputedUsage map[string]time.Duration SchedulerEnabled bool CDRSEnabled bool // Enable CDR Server service CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs @@ -917,6 +919,13 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnRALsCfg.Lcr_subject_prefix_matching != nil { self.LcrSubjectPrefixMatching = *jsnRALsCfg.Lcr_subject_prefix_matching } + if jsnRALsCfg.Max_computed_usage != nil { + for k, v := range *jsnRALsCfg.Max_computed_usage { + if self.RALsMaxComputedUsage[k], err = utils.ParseDurationWithNanosecs(v); err != nil { + return + } + } + } } if jsnSchedCfg != nil && jsnSchedCfg.Enabled != nil { self.SchedulerEnabled = *jsnSchedCfg.Enabled diff --git a/config/config_defaults.go b/config/config_defaults.go index 47312a995..d0a2dc4f7 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -138,7 +138,13 @@ const CGRATES_CFG_JSON = ` "users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234> "aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234> "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject - "lcr_subject_prefix_matching": false // enables prefix matching for the lcr subject + "lcr_subject_prefix_matching": false, // enables prefix matching for the lcr subject + "max_computed_usage": { // do not compute usage higher than this, prevents memory overload + "*any": "189h", + "*voice": "72h", + "*data": "107374182400", + "*sms": "10000" + }, }, diff --git a/config/config_json_test.go b/config/config_json_test.go index 96213618d..3f523547b 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -195,11 +195,23 @@ func TestDfStorDBJsonCfg(t *testing.T) { } func TestDfRalsJsonCfg(t *testing.T) { - eCfg := &RalsJsonCfg{Enabled: utils.BoolPointer(false), Thresholds_conns: &[]*HaPoolJsonCfg{}, - Cdrstats_conns: &[]*HaPoolJsonCfg{}, Stats_conns: &[]*HaPoolJsonCfg{}, - Historys_conns: &[]*HaPoolJsonCfg{}, Pubsubs_conns: &[]*HaPoolJsonCfg{}, - Users_conns: &[]*HaPoolJsonCfg{}, Aliases_conns: &[]*HaPoolJsonCfg{}, - Rp_subject_prefix_matching: utils.BoolPointer(false), Lcr_subject_prefix_matching: utils.BoolPointer(false)} + eCfg := &RalsJsonCfg{ + Enabled: utils.BoolPointer(false), + Thresholds_conns: &[]*HaPoolJsonCfg{}, + Cdrstats_conns: &[]*HaPoolJsonCfg{}, + Stats_conns: &[]*HaPoolJsonCfg{}, + Historys_conns: &[]*HaPoolJsonCfg{}, + Pubsubs_conns: &[]*HaPoolJsonCfg{}, + Users_conns: &[]*HaPoolJsonCfg{}, + Aliases_conns: &[]*HaPoolJsonCfg{}, + Rp_subject_prefix_matching: utils.BoolPointer(false), + Lcr_subject_prefix_matching: utils.BoolPointer(false), + Max_computed_usage: &map[string]string{ + utils.ANY: "189h", + utils.VOICE: "72h", + utils.DATA: "107374182400", + utils.SMS: "10000"}, + } if cfg, err := dfCgrJsonCfg.RalsJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { diff --git a/config/config_test.go b/config/config_test.go index a94433941..45beaa529 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -318,6 +318,15 @@ func TestCgrCfgJSONDefaultsRALs(t *testing.T) { if cgrCfg.LcrSubjectPrefixMatching != false { t.Error(cgrCfg.LcrSubjectPrefixMatching) } + eMaxCU := map[string]time.Duration{ + utils.ANY: time.Duration(189 * time.Hour), + utils.VOICE: time.Duration(72 * time.Hour), + utils.DATA: time.Duration(107374182400), + utils.SMS: time.Duration(10000), + } + if !reflect.DeepEqual(eMaxCU, cgrCfg.RALsMaxComputedUsage) { + t.Errorf("Expecting: %+v, received: %+v", eMaxCU, cgrCfg.RALsMaxComputedUsage) + } } func TestCgrCfgJSONDefaultsScheduler(t *testing.T) { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 5e464ecfc..42ff3ff64 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -89,6 +89,7 @@ type RalsJsonCfg struct { Users_conns *[]*HaPoolJsonCfg Rp_subject_prefix_matching *bool Lcr_subject_prefix_matching *bool + Max_computed_usage *map[string]string } // Scheduler config section