From 0da9a10de72b930d6ed583751bb048a17ddb48d8 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 30 Oct 2017 18:18:37 +0100 Subject: [PATCH 01/75] Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update --- apier/v1/auth.go | 3 - apier/v1/debit.go | 3 - apier/v1/debit_test.go | 1 - cdrc/csv_test.go | 41 +- cdrc/partial_cdr_test.go | 15 +- cdrc/xml_test.go | 12 +- cmd/cgr-tester/cdr_repl/process_cdr.go | 2 +- config/config_defaults.go | 3 - config/config_json_test.go | 8 - config/config_test.go | 100 ++-- config/configcdrc_test.go | 401 +++++++++----- console/maxusage.go | 2 +- data/storage/mysql/create_cdrs_tables.sql | 9 +- data/storage/postgres/create_cdrs_tables.sql | 9 +- engine/action.go | 15 +- engine/actions_test.go | 429 ++++++++++---- engine/cdr.go | 335 +++++------ engine/cdr_test.go | 323 ++++++----- engine/cdrecsv_test.go | 31 +- engine/cdrefwv_test.go | 67 ++- engine/cdrs.go | 34 +- engine/cdrstats.go | 17 - engine/cdrstats_queue.go | 1 - engine/cgrcdr.go | 4 - engine/cgrcdr_test.go | 61 +- engine/event.go | 4 - engine/fscdr.go | 7 - engine/fscdr_test.go | 13 +- engine/models.go | 121 ++-- engine/responder.go | 17 +- engine/responder_test.go | 190 ++++--- engine/statscdrs_test.go | 555 ------------------- engine/storage_mongo_datadb.go | 10 +- engine/storage_mongo_stordb.go | 12 +- engine/storage_sql.go | 176 ++---- engine/suretax_test.go | 15 +- engine/users_test.go | 7 - engine/version.go | 20 +- general_tests/auth_test.go | 8 +- general_tests/fsevcorelate_test.go | 12 - sessionmanager/fsevent.go | 4 - sessionmanager/fsevent_test.go | 39 +- sessionmanager/fssessionmanager.go | 2 +- sessionmanager/kamevent.go | 4 - sessionmanager/osipsevent.go | 4 - sessionmanager/osipsevent_test.go | 15 +- sessionmanager/session.go | 9 +- sessionmanager/smg_event.go | 4 - sessionmanager/smg_event_test.go | 10 +- sessionmanager/smg_session.go | 4 - utils/consts.go | 5 +- utils/coreutils.go | 11 + 52 files changed, 1405 insertions(+), 1799 deletions(-) delete mode 100644 engine/statscdrs_test.go diff --git a/apier/v1/auth.go b/apier/v1/auth.go index b952f3011..28b6b4945 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -38,9 +38,6 @@ func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float if usageRecord.RequestType == "" { usageRecord.RequestType = self.Config.DefaultReqType } - if usageRecord.Direction == "" { - usageRecord.Direction = utils.OUT - } if usageRecord.Tenant == "" { usageRecord.Tenant = self.Config.DefaultTenant } diff --git a/apier/v1/debit.go b/apier/v1/debit.go index a80d7fcdf..82f454e48 100644 --- a/apier/v1/debit.go +++ b/apier/v1/debit.go @@ -59,9 +59,6 @@ func (apier *ApierV1) DebitUsageWithOptions(args AttrDebitUsageWithOptions, repl if usageRecord.RequestType == "" { usageRecord.RequestType = apier.Config.DefaultReqType } - if usageRecord.Direction == "" { - usageRecord.Direction = utils.OUT - } if usageRecord.Tenant == "" { usageRecord.Tenant = apier.Config.DefaultTenant } diff --git a/apier/v1/debit_test.go b/apier/v1/debit_test.go index f5f8ad6dc..772b7b06a 100644 --- a/apier/v1/debit_test.go +++ b/apier/v1/debit_test.go @@ -125,7 +125,6 @@ func TestDebitUsageWithOptions(t *testing.T) { Usage: "1", ToR: utils.MONETARY, Category: "call", - Direction: "*out", SetupTime: time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC).String(), AnswerTime: time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC).String(), } diff --git a/cdrc/csv_test.go b/cdrc/csv_test.go index 83e80f28d..a207ab1dd 100644 --- a/cdrc/csv_test.go +++ b/cdrc/csv_test.go @@ -33,10 +33,6 @@ func TestCsvRecordToCDR(t *testing.T) { cdrcConfig.CdrSourceId = "TEST_CDRC" cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, FieldId: utils.MEDI_RUNID, Value: utils.ParseRSRFieldsMustCompile("^*default", utils.INFIELD_SEP)}) - cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "SupplierTest", Type: utils.META_COMPOSED, - FieldId: utils.SUPPLIER, Value: []*utils.RSRField{&utils.RSRField{Id: "14"}}}) - cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "DisconnectCauseTest", Type: utils.META_COMPOSED, - FieldId: utils.DISCONNECT_CAUSE, Value: []*utils.RSRField{&utils.RSRField{Id: "16"}}}) csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: []*config.CdrcConfig{cdrcConfig}} cdrRow := []string{"firstField", "secondField"} _, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig) @@ -50,26 +46,23 @@ func TestCsvRecordToCDR(t *testing.T) { t.Error("Failed to parse CDR in rated cdr", err) } expectedCdr := &engine.CDR{ - CGRID: utils.Sha1(cdrRow[3], time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC).String()), - RunID: "*default", - ToR: cdrRow[2], - OriginID: cdrRow[3], - OriginHost: "0.0.0.0", // Got it over internal interface - Source: "TEST_CDRC", - RequestType: cdrRow[4], - Direction: cdrRow[5], - Tenant: cdrRow[6], - Category: cdrRow[7], - Account: cdrRow[8], - Subject: cdrRow[9], - Destination: cdrRow[10], - SetupTime: time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC), - AnswerTime: time.Date(2013, 2, 3, 19, 54, 0, 0, time.UTC), - Usage: time.Duration(62) * time.Second, - Supplier: "supplier1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{}, - Cost: -1, + CGRID: utils.Sha1(cdrRow[3], time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC).String()), + RunID: "*default", + ToR: cdrRow[2], + OriginID: cdrRow[3], + OriginHost: "0.0.0.0", // Got it over internal interface + Source: "TEST_CDRC", + RequestType: cdrRow[4], + Tenant: cdrRow[6], + Category: cdrRow[7], + Account: cdrRow[8], + Subject: cdrRow[9], + Destination: cdrRow[10], + SetupTime: time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC), + AnswerTime: time.Date(2013, 2, 3, 19, 54, 0, 0, time.UTC), + Usage: time.Duration(62) * time.Second, + ExtraFields: map[string]string{}, + Cost: -1, } if !reflect.DeepEqual(expectedCdr, rtCdr) { t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr) diff --git a/cdrc/partial_cdr_test.go b/cdrc/partial_cdr_test.go index a8582a0d4..e6d7b8b01 100644 --- a/cdrc/partial_cdr_test.go +++ b/cdrc/partial_cdr_test.go @@ -39,8 +39,10 @@ func TestPartialCDRRecordSort(t *testing.T) { func TestPartialCDRRecordMergeCDRs(t *testing.T) { cdr1 := &engine.CDR{OrderID: 1, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: "TestPartialCDRRecordMergeCDRs", RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", + OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: "TestPartialCDRRecordMergeCDRs", RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), Partial: true, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } @@ -55,9 +57,12 @@ func TestPartialCDRRecordMergeCDRs(t *testing.T) { } pCdr := &PartialCDRRecord{cdrs: []*engine.CDR{cdr1, cdr2, cdr3}} eCDR := &engine.CDR{OrderID: 3, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: "TestPartialCDRRecordMergeCDRs", RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 43, 0, 0, time.UTC), Partial: false, + OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: "TestPartialCDRRecordMergeCDRs", RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 43, 0, 0, time.UTC), Partial: false, Usage: time.Duration(62 * time.Second), ExtraFields: map[string]string{"field_extr1": "val_extr11", "fieldextr2": "valextr2", "disconnect_direction": "upstream"}, } diff --git a/cdrc/xml_test.go b/cdrc/xml_test.go index 57f1e4f43..414fe7e49 100644 --- a/cdrc/xml_test.go +++ b/cdrc/xml_test.go @@ -221,8 +221,6 @@ func TestXMLRPProcess(t *testing.T) { Value: utils.ParseRSRFieldsMustCompile("broadWorksCDR>cdrData>basicModule>localCallId", utils.INFIELD_SEP), Mandatory: true}, &config.CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("^*rated", utils.INFIELD_SEP), Mandatory: true}, - &config.CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, FieldId: utils.DIRECTION, - Value: utils.ParseRSRFieldsMustCompile("^*out", utils.INFIELD_SEP), Mandatory: true}, &config.CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, Value: utils.ParseRSRFieldsMustCompile("~broadWorksCDR>cdrData>basicModule>userId:s/.*@(.*)/${1}/", utils.INFIELD_SEP), Mandatory: true}, &config.CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, @@ -255,9 +253,13 @@ func TestXMLRPProcess(t *testing.T) { t.Error(err) } expectedCDRs := []*engine.CDR{ - &engine.CDR{CGRID: "1f045359a0784d15e051d7e41ae30132b139d714", OriginHost: "0.0.0.0", Source: "TestXML", OriginID: "25160047719:0", - ToR: "*voice", RequestType: "*rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Destination: "+4986517174963", - SetupTime: time.Date(2016, 4, 19, 21, 0, 5, 247000000, time.UTC), AnswerTime: time.Date(2016, 4, 19, 21, 0, 6, 813000000, time.UTC), Usage: time.Duration(13483000000), + &engine.CDR{CGRID: "1f045359a0784d15e051d7e41ae30132b139d714", + OriginHost: "0.0.0.0", Source: "TestXML", OriginID: "25160047719:0", + ToR: "*voice", RequestType: "*rated", Tenant: "cgrates.org", + Category: "call", Account: "1001", Destination: "+4986517174963", + SetupTime: time.Date(2016, 4, 19, 21, 0, 5, 247000000, time.UTC), + AnswerTime: time.Date(2016, 4, 19, 21, 0, 6, 813000000, time.UTC), + Usage: time.Duration(13483000000), ExtraFields: map[string]string{}, Cost: -1}, } if !reflect.DeepEqual(expectedCDRs, cdrs) { diff --git a/cmd/cgr-tester/cdr_repl/process_cdr.go b/cmd/cgr-tester/cdr_repl/process_cdr.go index 299e90ad8..36a45997e 100644 --- a/cmd/cgr-tester/cdr_repl/process_cdr.go +++ b/cmd/cgr-tester/cdr_repl/process_cdr.go @@ -52,7 +52,7 @@ func main() { for i := 0; i < 10000; i++ { cdr := &engine.CDR{OriginID: fmt.Sprintf("httpjsonrpc_%d", i), ToR: utils.VOICE, OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} cdrs = append(cdrs, cdr) diff --git a/config/config_defaults.go b/config/config_defaults.go index d7ed88158..47312a995 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -180,7 +180,6 @@ const CGRATES_CFG_JSON = ` {"tag":"TOR", "type": "*composed", "value": "ToR"}, {"tag":"OriginID", "type": "*composed", "value": "OriginID"}, {"tag":"RequestType", "type": "*composed", "value": "RequestType"}, - {"tag":"Direction", "type": "*composed", "value": "Direction"}, {"tag":"Tenant", "type": "*composed", "value": "Tenant"}, {"tag":"Category", "type": "*composed", "value": "Category"}, {"tag":"Account", "type": "*composed", "value": "Account"}, @@ -230,7 +229,6 @@ const CGRATES_CFG_JSON = ` {"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "2", "mandatory": true}, {"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "3", "mandatory": true}, {"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "4", "mandatory": true}, - {"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "5", "mandatory": true}, {"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "6", "mandatory": true}, {"tag": "Category", "field_id": "Category", "type": "*composed", "value": "7", "mandatory": true}, {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "8", "mandatory": true}, @@ -247,7 +245,6 @@ const CGRATES_CFG_JSON = ` {"tag": "TOR", "type": "*composed", "value": "ToR"}, {"tag": "OriginID", "type": "*composed", "value": "OriginID"}, {"tag": "RequestType", "type": "*composed", "value": "RequestType"}, - {"tag": "Direction", "type": "*composed", "value": "Direction"}, {"tag": "Tenant", "type": "*composed", "value": "Tenant"}, {"tag": "Category", "type": "*composed", "value": "Category"}, {"tag": "Account", "type": "*composed", "value": "Account"}, diff --git a/config/config_json_test.go b/config/config_json_test.go index b51e32522..96213618d 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -272,9 +272,6 @@ func TestDfCdreJsonCfgs(t *testing.T) { &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)}, @@ -339,8 +336,6 @@ func TestDfCdrcJsonCfg(t *testing.T) { 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), @@ -374,9 +369,6 @@ func TestDfCdrcJsonCfg(t *testing.T) { &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)}, diff --git a/config/config_test.go b/config/config_test.go index 222571e59..a94433941 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -103,27 +103,45 @@ func TestCgrCfgCDRC(t *testing.T) { PartialCacheExpiryAction: "*dump_to_file", HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{FieldId: "ToR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP)}, - &CfgCdrField{FieldId: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP)}, - &CfgCdrField{FieldId: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP)}, + &CfgCdrField{FieldId: "ToR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP)}, + &CfgCdrField{FieldId: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP)}, + &CfgCdrField{FieldId: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP)}, }, TrailerFields: make([]*CfgCdrField, 0), CacheDumpFields: []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, }, }, } @@ -364,21 +382,37 @@ func TestCgrCfgJSONDefaultsCDRStats(t *testing.T) { func TestCgrCfgJSONDefaultsCdreProfiles(t *testing.T) { eFields := []*CfgCdrField{} eContentFlds := []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("CGRID", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("RunID", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("ToR", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("OriginID", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("RequestType", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Direction", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Tenant", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Category", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Account", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Subject", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Destination", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("SetupTime", utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("AnswerTime", utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Usage", utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("Cost", utils.INFIELD_SEP), RoundingDecimals: 4}, + &CfgCdrField{Tag: "CGRID", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("CGRID", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("RunID", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("ToR", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("OriginID", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("RequestType", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Tenant", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Category", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Account", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Subject", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Destination", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("SetupTime", utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("AnswerTime", utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Usage", utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: "*composed", + Value: utils.ParseRSRFieldsMustCompile("Cost", utils.INFIELD_SEP), + RoundingDecimals: 4}, } eCdreCfg := map[string]*CdreConfig{ "*default": { diff --git a/config/configcdrc_test.go b/config/configcdrc_test.go index caf7e5a52..ad69e2655 100644 --- a/config/configcdrc_test.go +++ b/config/configcdrc_test.go @@ -53,48 +53,81 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { PartialCacheExpiryAction: utils.MetaDumpToFile, HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, FieldId: utils.DIRECTION, Value: utils.ParseRSRFieldsMustCompile("5", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, + Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, + Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, + Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, + Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, + Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, + Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, + Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, + Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, + Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, + Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, + Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, TrailerFields: make([]*CfgCdrField, 0), CacheDumpFields: []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, }, }, } @@ -117,48 +150,81 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { PartialCacheExpiryAction: utils.MetaDumpToFile, HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, FieldId: utils.DIRECTION, Value: utils.ParseRSRFieldsMustCompile("5", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, + Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, + Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, + Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, + Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, + Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, + Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, + Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, + Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, + Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, + Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, + Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, TrailerFields: make([]*CfgCdrField, 0), CacheDumpFields: []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, }, }, } @@ -181,30 +247,51 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { PartialCacheExpiryAction: utils.MetaDumpToFile, HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, - &CfgCdrField{Tag: "", Type: "", FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, - &CfgCdrField{FieldId: utils.USAGE, Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, + &CfgCdrField{FieldId: utils.TOR, + Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, + &CfgCdrField{Tag: "", Type: "", FieldId: utils.ANSWER_TIME, + Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, + &CfgCdrField{FieldId: utils.USAGE, + Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, }, TrailerFields: make([]*CfgCdrField, 0), CacheDumpFields: []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, }, }, } @@ -227,52 +314,88 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { PartialCacheExpiryAction: utils.MetaDumpToFile, HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, FieldId: utils.DIRECTION, Value: utils.ParseRSRFieldsMustCompile("5", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), - FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, FieldId: utils.TOR, + Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, FieldId: utils.ACCID, + Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, + Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, FieldId: utils.TENANT, + Value: utils.ParseRSRFieldsMustCompile("6", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, FieldId: utils.CATEGORY, + Value: utils.ParseRSRFieldsMustCompile("7", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, FieldId: utils.ACCOUNT, + Value: utils.ParseRSRFieldsMustCompile("8", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, FieldId: utils.SUBJECT, + Value: utils.ParseRSRFieldsMustCompile("9", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, + Value: utils.ParseRSRFieldsMustCompile("10", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, + Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, + Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, FieldId: utils.USAGE, + Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), + FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), + Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, TrailerFields: make([]*CfgCdrField, 0), CacheDumpFields: []*CfgCdrField{ - &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, - &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, - &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), + Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, }, }, } if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) { - t.Errorf("Expected: \n%s\n, received: \n%s\n", utils.ToJSON(eCgrCfg.CdrcProfiles), utils.ToJSON(cgrCfg.CdrcProfiles)) + t.Errorf("Expected: \n%s\n, received: \n%s\n", + utils.ToJSON(eCgrCfg.CdrcProfiles), utils.ToJSON(cgrCfg.CdrcProfiles)) } } diff --git a/console/maxusage.go b/console/maxusage.go index ea0d5051b..f49858d6d 100644 --- a/console/maxusage.go +++ b/console/maxusage.go @@ -48,7 +48,7 @@ func (self *CmdGetMaxUsage) RpcMethod() string { func (self *CmdGetMaxUsage) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { - self.rpcParams = &engine.UsageRecord{Direction: "*out"} + self.rpcParams = &engine.UsageRecord{} } return self.rpcParams } diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql index 40598db44..4423044ec 100644 --- a/data/storage/mysql/create_cdrs_tables.sql +++ b/data/storage/mysql/create_cdrs_tables.sql @@ -12,23 +12,18 @@ CREATE TABLE cdrs ( origin_id varchar(64) NOT NULL, tor varchar(16) NOT NULL, request_type varchar(24) NOT NULL, - direction varchar(8) NOT NULL, tenant varchar(64) NOT NULL, category varchar(32) NOT NULL, account varchar(128) NOT NULL, subject varchar(128) NOT NULL, destination varchar(128) NOT NULL, setup_time datetime NOT NULL, - pdd DECIMAL(12,9) NOT NULL, answer_time datetime NOT NULL, - `usage` DECIMAL(30,9) NOT NULL, - supplier varchar(128) NOT NULL, - disconnect_cause varchar(64) NOT NULL, + `usage` BIGINT NOT NULL, extra_fields text NOT NULL, cost_source varchar(64) NOT NULL, cost DECIMAL(20,4) NOT NULL, cost_details text, - account_summary text, extra_info text, created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, @@ -45,7 +40,7 @@ CREATE TABLE sm_costs ( origin_host varchar(64) NOT NULL, origin_id varchar(64) NOT NULL, cost_source varchar(64) NOT NULL, - `usage` DECIMAL(30,9) NOT NULL, + `usage` BIGINT NOT NULL, cost_details text, created_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, diff --git a/data/storage/postgres/create_cdrs_tables.sql b/data/storage/postgres/create_cdrs_tables.sql index 1cb0cff64..9b5c9c4fe 100644 --- a/data/storage/postgres/create_cdrs_tables.sql +++ b/data/storage/postgres/create_cdrs_tables.sql @@ -12,23 +12,18 @@ CREATE TABLE cdrs ( origin_id VARCHAR(64) NOT NULL, tor VARCHAR(16) NOT NULL, request_type VARCHAR(24) NOT NULL, - direction VARCHAR(8) NOT NULL, tenant VARCHAR(64) NOT NULL, category VARCHAR(32) NOT NULL, account VARCHAR(128) NOT NULL, subject VARCHAR(128) NOT NULL, destination VARCHAR(128) NOT NULL, setup_time TIMESTAMP WITH TIME ZONE NOT NULL, - pdd NUMERIC(12,9) NOT NULL, answer_time TIMESTAMP WITH TIME ZONE NOT NULL, - usage NUMERIC(30,9) NOT NULL, - supplier VARCHAR(128) NOT NULL, - disconnect_cause VARCHAR(64) NOT NULL, + usage BIGINT NOT NULL, extra_fields jsonb NOT NULL, cost_source VARCHAR(64) NOT NULL, cost NUMERIC(20,4) DEFAULT NULL, cost_details jsonb, - account_summary jsonb, extra_info text, created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE NULL, @@ -48,7 +43,7 @@ CREATE TABLE sm_costs ( origin_host VARCHAR(64) NOT NULL, origin_id VARCHAR(64) NOT NULL, cost_source VARCHAR(64) NOT NULL, - usage NUMERIC(30,9) NOT NULL, + usage BIGINT NOT NULL, cost_details jsonb, created_at TIMESTAMP WITH TIME ZONE, deleted_at TIMESTAMP WITH TIME ZONE NULL, diff --git a/engine/action.go b/engine/action.go index fe5627eb0..e6eec5205 100644 --- a/engine/action.go +++ b/engine/action.go @@ -187,14 +187,13 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) func cdrLogAction(acc *Account, sq *CDRStatsQueueTriggered, a *Action, acs Actions) (err error) { defaultTemplate := map[string]utils.RSRFields{ - utils.TOR: utils.ParseRSRFieldsMustCompile("BalanceType", utils.INFIELD_SEP), - utils.CDRHOST: utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), - utils.DIRECTION: utils.ParseRSRFieldsMustCompile("Directions", utils.INFIELD_SEP), - utils.REQTYPE: utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), - utils.TENANT: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP), - utils.ACCOUNT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), - utils.SUBJECT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), - utils.COST: utils.ParseRSRFieldsMustCompile("ActionValue", utils.INFIELD_SEP), + utils.TOR: utils.ParseRSRFieldsMustCompile("BalanceType", utils.INFIELD_SEP), + utils.CDRHOST: utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), + utils.REQTYPE: utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), + utils.TENANT: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP), + utils.ACCOUNT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), + utils.SUBJECT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), + utils.COST: utils.ParseRSRFieldsMustCompile("ActionValue", utils.INFIELD_SEP), } template := make(map[string]string) diff --git a/engine/actions_test.go b/engine/actions_test.go index 59e4b0e92..28767e61b 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -113,14 +113,16 @@ func TestActionPlanOnlyWeekdays(t *testing.T) { } func TestActionPlanHourWeekdays(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{ + WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) y, m, d := now.Date() e := time.Date(y, m, d, 10, 1, 0, 0, time.Local) day := e.Day() for i := 0; i < 8; i++ { - e = time.Date(e.Year(), e.Month(), day, e.Hour(), e.Minute(), e.Second(), e.Nanosecond(), e.Location()) + e = time.Date(e.Year(), e.Month(), day, e.Hour(), + e.Minute(), e.Second(), e.Nanosecond(), e.Location()) n := e.AddDate(0, 0, i) if n.Weekday() == time.Monday && (n.Equal(now) || n.After(now)) { e = n @@ -136,7 +138,8 @@ func TestActionPlanOnlyMonthdays(t *testing.T) { y, m, d := now.Date() tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}} + at := &ActionTiming{Timing: &RateInterval{ + Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}} st := at.GetNextStartTime(referenceDate) expected := tomorrow if !st.Equal(expected) { @@ -152,7 +155,8 @@ func TestActionPlanHourMonthdays(t *testing.T) { if now.After(testTime) { y, m, d = tomorrow.Date() } - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{ + Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -164,7 +168,8 @@ func TestActionPlanOnlyMonths(t *testing.T) { y, m, _ := now.Date() nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} + at := &ActionTiming{Timing: &RateInterval{ + Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(nextMonth.Year(), nextMonth.Month(), 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -250,7 +255,8 @@ func TestActionPlanFirstOfTheMonth(t *testing.T) { func TestActionPlanOnlyYears(t *testing.T) { y, _, _ := referenceDate.Date() nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} + at := &ActionTiming{Timing: &RateInterval{ + Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} st := at.GetNextStartTime(referenceDate) expected := nextYear if !st.Equal(expected) { @@ -268,7 +274,8 @@ func TestActionPlanPast(t *testing.T) { } func TestActionPlanHourYears(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{ + Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(referenceDate.Year(), 1, 1, 10, 1, 0, 0, time.Local) if referenceDate.After(expected) { @@ -447,8 +454,10 @@ func TestActionPlanFunctionNotAvailable(t *testing.T) { func TestActionTimingPriorityListSortByWeight(t *testing.T) { at1 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2020}, - Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + Years: utils.Years{2020}, + Months: utils.Months{time.January, time.February, time.March, + time.April, time.May, time.June, time.July, time.August, time.September, + time.October, time.November, time.December}, MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, @@ -456,8 +465,10 @@ func TestActionTimingPriorityListSortByWeight(t *testing.T) { }} at2 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2020}, - Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + Years: utils.Years{2020}, + Months: utils.Months{time.January, time.February, time.March, + time.April, time.May, time.June, time.July, time.August, time.September, + time.October, time.November, time.December}, MonthDays: utils.MonthDays{2}, StartTime: "00:00:00", }, @@ -475,7 +486,9 @@ func TestActionTimingPriorityListWeight(t *testing.T) { at1 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ - Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + Months: utils.Months{time.January, time.February, time.March, + time.April, time.May, time.June, time.July, time.August, time.September, + time.October, time.November, time.December}, MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, @@ -485,7 +498,9 @@ func TestActionTimingPriorityListWeight(t *testing.T) { at2 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ - Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, + Months: utils.Months{time.January, time.February, time.March, + time.April, time.May, time.June, time.July, time.August, time.September, + time.October, time.November, time.December}, MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", }, @@ -550,26 +565,33 @@ func TestActionPlansRemoveMember(t *testing.T) { }, } - if err := dm.DataDB().SetActionPlan(ap1.Id, ap1, true, utils.NonTransactional); err != nil { + if err := dm.DataDB().SetActionPlan(ap1.Id, ap1, true, + utils.NonTransactional); err != nil { t.Error(err) } - if err = dm.DataDB().SetActionPlan(ap2.Id, ap2, true, utils.NonTransactional); err != nil { + if err = dm.DataDB().SetActionPlan(ap2.Id, ap2, true, + utils.NonTransactional); err != nil { t.Error(err) } - if err = dm.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, []string{ap1.Id, ap2.Id}, true); err != nil { + if err = dm.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, + []string{ap1.Id, ap2.Id}, true); err != nil { t.Error(err) } - if err = dm.DataDB().SetAccountActionPlans(account1.ID, []string{ap1.Id}, false); err != nil { + if err = dm.DataDB().SetAccountActionPlans(account1.ID, + []string{ap1.Id}, false); err != nil { t.Error(err) } - if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{account1.ID}, true); err != nil { + if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix, + []string{account1.ID}, true); err != nil { t.Error(err) } dm.DataDB().GetAccountActionPlans(account1.ID, true, utils.NonTransactional) // FixMe: remove here after finishing testing of map - if err = dm.DataDB().SetAccountActionPlans(account2.ID, []string{ap2.Id}, false); err != nil { + if err = dm.DataDB().SetAccountActionPlans(account2.ID, + []string{ap2.Id}, false); err != nil { t.Error(err) } - if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{account2.ID}, false); err != nil { + if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix, + []string{account2.ID}, false); err != nil { t.Error(err) } @@ -643,7 +665,8 @@ func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: `{"BalanceDirections":"*out"}`} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ExtraParameters: `{"BalanceDirections":"*out"}`} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -658,7 +681,8 @@ func TestActionTriggerMatchMinuteBucketFull(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v}`, utils.TRIGGER_MAX_BALANCE, 2)} + a := &Action{ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v}`, + utils.TRIGGER_MAX_BALANCE, 2)} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -673,7 +697,9 @@ func TestActionTriggerMatchAllFull(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 2)} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, + utils.TRIGGER_MAX_BALANCE, 2)} if !at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -688,7 +714,9 @@ func TestActionTriggerMatchSomeFalse(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%s"}`, utils.TRIGGER_MAX_BALANCE_COUNTER)} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%s"}`, + utils.TRIGGER_MAX_BALANCE_COUNTER)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -703,7 +731,9 @@ func TestActionTriggerMatcBalanceFalse(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ExtraParameters: fmt.Sprintf(`{"GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ExtraParameters: fmt.Sprintf(`{"GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -718,7 +748,8 @@ func TestActionTriggerMatcAllFalse(t *testing.T) { ThresholdType: utils.TRIGGER_MAX_BALANCE, ThresholdValue: 2, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)} if at.Match(a) { t.Errorf("Action trigger [%v] does not match action [%v]", at, a) } @@ -767,10 +798,15 @@ func TestActionTriggers(t *testing.T) { func TestActionResetTriggres(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 10}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 10}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) if ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true { @@ -780,10 +816,12 @@ func TestActionResetTriggres(t *testing.T) { func TestActionResetTriggresExecutesThem(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 10}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 10}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, nil, nil) if ub.ActionTriggers[0].Executed == true || ub.BalanceMap[utils.MONETARY][0].GetValue() == 12 { @@ -793,10 +831,18 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { func TestActionResetTriggresActionFilter(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 10}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{utils.MONETARY: Balances{ + &Balance{Value: 10}}, utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } resetTriggersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}}, nil) if ub.ActionTriggers[0].Executed == false || ub.ActionTriggers[1].Executed == false { @@ -806,10 +852,19 @@ func TestActionResetTriggresActionFilter(t *testing.T) { func TestActionSetPostpaid(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } allowNegativeAction(ub, nil, nil, nil) if !ub.AllowNegative { @@ -819,11 +874,20 @@ func TestActionSetPostpaid(t *testing.T) { func TestActionSetPrepaid(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - AllowNegative: true, - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + AllowNegative: true, + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } denyNegativeAction(ub, nil, nil, nil) if ub.AllowNegative { @@ -833,11 +897,20 @@ func TestActionSetPrepaid(t *testing.T) { func TestActionResetPrepaid(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - AllowNegative: true, - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + AllowNegative: true, + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) if !ub.AllowNegative || @@ -852,10 +925,19 @@ func TestActionResetPrepaid(t *testing.T) { func TestActionResetPostpaid(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } resetAccountAction(ub, nil, nil, nil) if ub.BalanceMap[utils.MONETARY].GetTotalValue() != 0 || @@ -868,12 +950,26 @@ func TestActionResetPostpaid(t *testing.T) { func TestActionTopupResetCredit(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, + Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupResetAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 10 || @@ -913,7 +1009,8 @@ func TestActionTopupResetCreditId(t *testing.T) { }, }, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), + Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupResetAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 || @@ -932,7 +1029,8 @@ func TestActionTopupResetCreditNoId(t *testing.T) { }, }, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupResetAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 20 || @@ -946,11 +1044,22 @@ func TestActionTopupResetMinutes(t *testing.T) { ID: "TEST_UB", BalanceMap: map[string]Balances{ utils.MONETARY: Balances{&Balance{Value: 100}}, - utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), + Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, + Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), + Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupResetAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE].GetTotalValue() != 5 || @@ -964,12 +1073,27 @@ func TestActionTopupResetMinutes(t *testing.T) { func TestActionTopupCredit(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), + Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, + DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, + Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}, + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 || @@ -982,12 +1106,23 @@ func TestActionTopupCredit(t *testing.T) { func TestActionTopupMinutes(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), + Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), + Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} topupAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE].GetTotalValue() != 15 || @@ -1001,12 +1136,26 @@ func TestActionTopupMinutes(t *testing.T) { func TestActionDebitCredit(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, + Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}, + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} debitAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.MONETARY].GetTotalValue() != 90 || @@ -1019,12 +1168,25 @@ func TestActionDebitCredit(t *testing.T) { func TestActionDebitMinutes(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10, Weight: 20, + DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}, + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} + a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), + Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}} debitAction(ub, nil, a, nil) if ub.AllowNegative || ub.BalanceMap[utils.VOICE][0].GetValue() != 5 || @@ -1043,10 +1205,16 @@ func TestActionResetAllCounters(t *testing.T) { BalanceMap: map[string]Balances{ utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{ - &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, - &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT)}}}, + &Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT"), + Directions: utils.NewStringMap(utils.OUT)}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET"), + Directions: utils.NewStringMap(utils.OUT)}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Weight: utils.Float64Pointer(20)}, ActionsID: "TEST_ACTIONS", Executed: true}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, + Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), + Weight: utils.Float64Pointer(20)}, ActionsID: "TEST_ACTIONS", Executed: true}}, } ub.InitCounters() resetCountersAction(ub, nil, nil, nil) @@ -1056,13 +1224,15 @@ func TestActionResetAllCounters(t *testing.T) { len(ub.UnitCounters[utils.MONETARY][0].Counters) != 1 || len(ub.BalanceMap[utils.MONETARY]) != 1 || ub.ActionTriggers[0].Executed != true { - t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[utils.MONETARY][0], ub.UnitCounters[utils.MONETARY][0].Counters[0]) + t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, + ub.UnitCounters[utils.MONETARY][0], ub.UnitCounters[utils.MONETARY][0].Counters[0]) } if len(ub.UnitCounters) < 1 { t.FailNow() } c := ub.UnitCounters[utils.MONETARY][0].Counters[0] - if c.Filter.GetWeight() != 20 || c.Value != 0 || c.Filter.GetDestinationIDs()["NAT"] == false { + if c.Filter.GetWeight() != 20 || c.Value != 0 || + c.Filter.GetDestinationIDs()["NAT"] == false { t.Errorf("Balance cloned incorrectly: %+v", c) } } @@ -1073,8 +1243,13 @@ func TestActionResetCounterOnlyDefault(t *testing.T) { AllowNegative: true, BalanceMap: map[string]Balances{ utils.MONETARY: Balances{&Balance{Value: 100}}, - utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, + DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, + DestinationIDs: utils.NewStringMap("RET")}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, + ActionsID: "TEST_ACTIONS", Executed: true}}, } a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}} ub.InitCounters() @@ -1101,11 +1276,23 @@ func TestActionResetCounterOnlyDefault(t *testing.T) { func TestActionResetCounterCredit(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - AllowNegative: true, - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}, utils.SMS: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, + ID: "TEST_UB", + AllowNegative: true, + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{Value: 100}}, + utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")}, + &Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{ + &CounterFilter{Value: 1, Filter: &BalanceFilter{ + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}, + utils.SMS: []*UnitCounter{&UnitCounter{ + Counters: CounterFilters{&CounterFilter{Value: 1, + Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}} resetCountersAction(ub, nil, a, nil) @@ -1159,8 +1346,10 @@ func TestActionTriggerLogging(t *testing.T) { func TestActionPlanLogging(t *testing.T) { i := &RateInterval{ Timing: &RITiming{ - Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, - MonthDays: utils.MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, + time.July, time.August, time.September, time.October, time.November, time.December}, + MonthDays: utils.MonthDays{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, WeekDays: utils.WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, StartTime: "18:00:00", EndTime: "00:00:00", @@ -1236,7 +1425,9 @@ func TestTopupAction(t *testing.T) { initialUb, _ := dm.DataDB().GetAccount("vdf:minu") a := &Action{ ActionType: TOPUP, - Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)}, } at := &ActionTiming{ @@ -1257,7 +1448,9 @@ func TestTopupActionLoaded(t *testing.T) { initialUb, _ := dm.DataDB().GetAccount("vdf:minitsboy") a := &Action{ ActionType: TOPUP, - Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)}, } at := &ActionTiming{ @@ -1284,7 +1477,8 @@ func TestActionCdrlogEmpty(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1306,11 +1500,13 @@ func TestActionCdrlogWithParams(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1333,11 +1529,13 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, &Action{ ActionType: DEBIT_RESET, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 25}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)}, }, }) if err != nil { @@ -1358,7 +1556,8 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { } func TestActionSetDDestination(t *testing.T) { - acc := &Account{BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{DestinationIDs: utils.NewStringMap("*ddc_test")}}}} + acc := &Account{BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{&Balance{DestinationIDs: utils.NewStringMap("*ddc_test")}}}} origD := &Destination{Id: "*ddc_test", Prefixes: []string{"111", "222"}} dm.DataDB().SetDestination(origD, utils.NonTransactional) dm.DataDB().SetReverseDestination(origD, utils.NonTransactional) @@ -1425,11 +1624,13 @@ func TestActionTransactionFuncType(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, + Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ ActionType: "VALID_FUNCTION_TYPE", - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, Type: utils.StringPointer("test")}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, + Type: utils.StringPointer("test")}, }, }, } @@ -1461,7 +1662,8 @@ func TestActionTransactionBalanceType(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.MONETARY)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, + Type: utils.StringPointer(utils.MONETARY)}, }, &Action{ ActionType: TOPUP, @@ -1497,7 +1699,8 @@ func TestActionTransactionBalanceNotType(t *testing.T) { actions: []*Action{ &Action{ ActionType: TOPUP, - Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, Type: utils.StringPointer(utils.VOICE)}, + Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1}, + Type: utils.StringPointer(utils.VOICE)}, }, &Action{ ActionType: TOPUP, diff --git a/engine/cdr.go b/engine/cdr.go index 6b225777d..d2fbd3a97 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -32,10 +32,11 @@ import ( func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { var err error - cdr := &CDR{CGRID: extCdr.CGRID, RunID: extCdr.RunID, OrderID: extCdr.OrderID, ToR: extCdr.ToR, OriginID: extCdr.OriginID, OriginHost: extCdr.OriginHost, - Source: extCdr.Source, RequestType: extCdr.RequestType, Direction: extCdr.Direction, Tenant: extCdr.Tenant, Category: extCdr.Category, - Account: extCdr.Account, Subject: extCdr.Subject, Destination: extCdr.Destination, Supplier: extCdr.Supplier, - DisconnectCause: extCdr.DisconnectCause, CostSource: extCdr.CostSource, Cost: extCdr.Cost, Rated: extCdr.Rated} + cdr := &CDR{CGRID: extCdr.CGRID, RunID: extCdr.RunID, OrderID: extCdr.OrderID, ToR: extCdr.ToR, + OriginID: extCdr.OriginID, OriginHost: extCdr.OriginHost, + Source: extCdr.Source, RequestType: extCdr.RequestType, Tenant: extCdr.Tenant, Category: extCdr.Category, + Account: extCdr.Account, Subject: extCdr.Subject, Destination: extCdr.Destination, + CostSource: extCdr.CostSource, Cost: extCdr.Cost, Rated: extCdr.Rated} if extCdr.SetupTime != "" { if cdr.SetupTime, err = utils.ParseTimeDetectLayout(extCdr.SetupTime, timezone); err != nil { return nil, err @@ -54,11 +55,6 @@ func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { return nil, err } } - if extCdr.PDD != "" { - if cdr.PDD, err = utils.ParseDurationWithSecs(extCdr.PDD); err != nil { - return nil, err - } - } if len(extCdr.CostDetails) != 0 { if err = json.Unmarshal([]byte(extCdr.CostDetails), cdr.CostDetails); err != nil { return nil, err @@ -74,39 +70,35 @@ func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { } func NewCDRWithDefaults(cfg *config.CGRConfig) *CDR { - return &CDR{ToR: utils.VOICE, RequestType: cfg.DefaultReqType, Direction: utils.OUT, Tenant: cfg.DefaultTenant, Category: cfg.DefaultCategory, + return &CDR{ToR: utils.VOICE, RequestType: cfg.DefaultReqType, + Tenant: cfg.DefaultTenant, Category: cfg.DefaultCategory, ExtraFields: make(map[string]string), Cost: -1} } type CDR struct { - CGRID string - RunID string - OrderID int64 // Stor order id used as export order id - OriginHost string // represents the IP address of the host generating the CDR (automatically populated by the server) - Source string // formally identifies the source of the CDR (free form field) - OriginID string // represents the unique accounting id given by the telecom switch generating the CDR - ToR string // type of record, meta-field, should map to one of the TORs hardcoded inside the server <*voice|*data|*sms|*generic> - RequestType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server . - Direction string // matching the supported direction identifiers of the CGRateS <*out> - Tenant string // tenant whom this record belongs - Category string // free-form filter for this record, matching the category defined in rating profiles. - Account string // account id (accounting subsystem) the record should be attached to - Subject string // rating subject (rating subsystem) this record should be attached to - Destination string // destination to be charged - SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. - PDD time.Duration // PDD value - AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. - Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call) - Supplier string // Supplier information when available - DisconnectCause string // Disconnect cause of the event - ExtraFields map[string]string // Extra fields to be stored in CDR - CostSource string // The source of this cost - Cost float64 - CostDetails *CallCost // Attach the cost details to CDR when possible - AccountSummary *AccountSummary // Store AccountSummary information - ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation - Rated bool // Mark the CDR as rated so we do not process it during rating - Partial bool // Used for partial record processing by CDRC + CGRID string + RunID string + OrderID int64 // Stor order id used as export order id + OriginHost string // represents the IP address of the host generating the CDR (automatically populated by the server) + Source string // formally identifies the source of the CDR (free form field) + OriginID string // represents the unique accounting id given by the telecom switch generating the CDR + ToR string // type of record, meta-field, should map to one of the TORs hardcoded inside the server <*voice|*data|*sms|*generic> + RequestType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server . + Tenant string // tenant whom this record belongs + Category string // free-form filter for this record, matching the category defined in rating profiles. + Account string // account id (accounting subsystem) the record should be attached to + Subject string // rating subject (rating subsystem) this record should be attached to + Destination string // destination to be charged + SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. + AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. + Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call) + ExtraFields map[string]string // Extra fields to be stored in CDR + ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation + Partial bool // Used for partial record processing by CDRC + Rated bool // Mark the CDR as rated so we do not process it during rating + CostSource string // The source of this cost + Cost float64 + CostDetails *CallCost // Attach the cost details to CDR when possible } func (cdr *CDR) CostDetailsJson() string { @@ -114,11 +106,6 @@ func (cdr *CDR) CostDetailsJson() string { return string(mrshled) } -func (cdr *CDR) AccountSummaryJson() string { - mrshled, _ := json.Marshal(cdr.AccountSummary) - return string(mrshled) -} - func (cdr *CDR) ComputeCGRID() { cdr.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.UTC().String()) } @@ -173,8 +160,6 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { return rsrFld.ParseValue(cdr.Source) case utils.REQTYPE: return rsrFld.ParseValue(cdr.RequestType) - case utils.DIRECTION: - return rsrFld.ParseValue(cdr.Direction) case utils.TENANT: return rsrFld.ParseValue(cdr.Tenant) case utils.CATEGORY: @@ -187,16 +172,10 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { return rsrFld.ParseValue(cdr.Destination) case utils.SETUP_TIME: return rsrFld.ParseValue(cdr.SetupTime.Format(time.RFC3339)) - case utils.PDD: - return strconv.FormatFloat(cdr.PDD.Seconds(), 'f', -1, 64) case utils.ANSWER_TIME: return rsrFld.ParseValue(cdr.AnswerTime.Format(time.RFC3339)) case utils.USAGE: return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) - case utils.SUPPLIER: - return rsrFld.ParseValue(cdr.Supplier) - case utils.DISCONNECT_CAUSE: - return rsrFld.ParseValue(cdr.DisconnectCause) case utils.MEDI_RUNID: return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: @@ -205,8 +184,6 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { return rsrFld.ParseValue(strconv.FormatFloat(cdr.Cost, 'f', -1, 64)) // Recommended to use FormatCost case utils.COST_DETAILS: return rsrFld.ParseValue(cdr.CostDetailsJson()) - case utils.ACCOUNT_SUMMARY: - return rsrFld.ParseValue(cdr.AccountSummaryJson()) case utils.PartialField: return rsrFld.ParseValue(strconv.FormatBool(cdr.Partial)) default: @@ -230,8 +207,6 @@ func (cdr *CDR) ParseFieldValue(fieldId, fieldVal, timezone string) error { cdr.OriginID += fieldVal case utils.REQTYPE: cdr.RequestType += fieldVal - case utils.DIRECTION: - cdr.Direction += fieldVal case utils.TENANT: cdr.Tenant += fieldVal case utils.CATEGORY: @@ -248,10 +223,6 @@ func (cdr *CDR) ParseFieldValue(fieldId, fieldVal, timezone string) error { if cdr.SetupTime, err = utils.ParseTimeDetectLayout(fieldVal, timezone); err != nil { return fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) } - case utils.PDD: - if cdr.PDD, err = utils.ParseDurationWithSecs(fieldVal); err != nil { - return fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) - } case utils.ANSWER_TIME: if cdr.AnswerTime, err = utils.ParseTimeDetectLayout(fieldVal, timezone); err != nil { return fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) @@ -260,10 +231,6 @@ func (cdr *CDR) ParseFieldValue(fieldId, fieldVal, timezone string) error { if cdr.Usage, err = utils.ParseDurationWithSecs(fieldVal); err != nil { return fmt.Errorf("Cannot parse duration field with value: %s, err: %s", fieldVal, err.Error()) } - case utils.SUPPLIER: - cdr.Supplier += fieldVal - case utils.DISCONNECT_CAUSE: - cdr.DisconnectCause += fieldVal case utils.COST: if cdr.Cost, err = strconv.ParseFloat(fieldVal, 64); err != nil { return fmt.Errorf("Cannot parse cost field with value: %s, err: %s", fieldVal, err.Error()) @@ -296,8 +263,8 @@ func (cdr *CDR) Clone() *CDR { } // Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored -func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, PDDFld, - answerTimeFld, durationFld, supplierFld, disconnectCauseFld, ratedFld, costFld *utils.RSRField, +func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, + answerTimeFld, durationFld, ratedFld, costFld *utils.RSRField, extraFlds []*utils.RSRField, primaryMandatory bool, timezone string) (*CDR, error) { if RequestTypeFld == nil { RequestTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT) @@ -305,12 +272,6 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, c if RequestTypeFld.Id == utils.META_DEFAULT { RequestTypeFld.Id = utils.REQTYPE } - if directionFld == nil { - directionFld, _ = utils.NewRSRField(utils.META_DEFAULT) - } - if directionFld.Id == utils.META_DEFAULT { - directionFld.Id = utils.DIRECTION - } if tenantFld == nil { tenantFld, _ = utils.NewRSRField(utils.META_DEFAULT) } @@ -359,24 +320,6 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, c if durationFld.Id == utils.META_DEFAULT { durationFld.Id = utils.USAGE } - if PDDFld == nil { - PDDFld, _ = utils.NewRSRField(utils.META_DEFAULT) - } - if PDDFld.Id == utils.META_DEFAULT { - PDDFld.Id = utils.PDD - } - if supplierFld == nil { - supplierFld, _ = utils.NewRSRField(utils.META_DEFAULT) - } - if supplierFld.Id == utils.META_DEFAULT { - supplierFld.Id = utils.SUPPLIER - } - if disconnectCauseFld == nil { - disconnectCauseFld, _ = utils.NewRSRField(utils.META_DEFAULT) - } - if disconnectCauseFld.Id == utils.META_DEFAULT { - disconnectCauseFld.Id = utils.DISCONNECT_CAUSE - } if ratedFld == nil { ratedFld, _ = utils.NewRSRField(utils.META_DEFAULT) } @@ -402,10 +345,6 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, c if primaryMandatory && len(frkStorCdr.RequestType) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.REQTYPE, RequestTypeFld.Id) } - frkStorCdr.Direction = cdr.FieldAsString(directionFld) - if primaryMandatory && len(frkStorCdr.Direction) == 0 { - return nil, utils.NewErrMandatoryIeMissing(utils.DIRECTION, directionFld.Id) - } frkStorCdr.Tenant = cdr.FieldAsString(tenantFld) if primaryMandatory && len(frkStorCdr.Tenant) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.TENANT, tenantFld.Id) @@ -444,14 +383,6 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, c } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { return nil, err } - PDDStr := cdr.FieldAsString(PDDFld) - if primaryMandatory && len(PDDStr) == 0 { - return nil, utils.NewErrMandatoryIeMissing(utils.PDD, PDDFld.Id) - } else if frkStorCdr.PDD, err = utils.ParseDurationWithSecs(PDDStr); err != nil { - return nil, err - } - frkStorCdr.Supplier = cdr.FieldAsString(supplierFld) - frkStorCdr.DisconnectCause = cdr.FieldAsString(disconnectCauseFld) ratedStr := cdr.FieldAsString(ratedFld) if primaryMandatory && len(ratedStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.RATED_FLD, ratedFld.Id) @@ -473,31 +404,27 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, c func (cdr *CDR) AsExternalCDR() *ExternalCDR { return &ExternalCDR{CGRID: cdr.CGRID, - RunID: cdr.RunID, - OrderID: cdr.OrderID, - OriginHost: cdr.OriginHost, - Source: cdr.Source, - OriginID: cdr.OriginID, - ToR: cdr.ToR, - RequestType: cdr.RequestType, - Direction: cdr.Direction, - Tenant: cdr.Tenant, - Category: cdr.Category, - Account: cdr.Account, - Subject: cdr.Subject, - Destination: cdr.Destination, - SetupTime: cdr.SetupTime.Format(time.RFC3339), - PDD: cdr.FieldAsString(&utils.RSRField{Id: utils.PDD}), - AnswerTime: cdr.AnswerTime.Format(time.RFC3339), - Usage: cdr.FormatUsage(utils.SECONDS), - Supplier: cdr.Supplier, - DisconnectCause: cdr.DisconnectCause, - ExtraFields: cdr.ExtraFields, - CostSource: cdr.CostSource, - Cost: cdr.Cost, - CostDetails: cdr.CostDetailsJson(), - ExtraInfo: cdr.ExtraInfo, - Rated: cdr.Rated, + RunID: cdr.RunID, + OrderID: cdr.OrderID, + OriginHost: cdr.OriginHost, + Source: cdr.Source, + OriginID: cdr.OriginID, + ToR: cdr.ToR, + RequestType: cdr.RequestType, + Tenant: cdr.Tenant, + Category: cdr.Category, + Account: cdr.Account, + Subject: cdr.Subject, + Destination: cdr.Destination, + SetupTime: cdr.SetupTime.Format(time.RFC3339), + AnswerTime: cdr.AnswerTime.Format(time.RFC3339), + Usage: cdr.FormatUsage(utils.SECONDS), + ExtraFields: cdr.ExtraFields, + CostSource: cdr.CostSource, + Cost: cdr.Cost, + CostDetails: cdr.CostDetailsJson(), + ExtraInfo: cdr.ExtraInfo, + Rated: cdr.Rated, } } @@ -520,15 +447,6 @@ func (cdr *CDR) GetUUID() string { func (cdr *CDR) GetSessionIds() []string { return []string{cdr.GetUUID()} } -func (cdr *CDR) GetDirection(fieldName string) string { - if utils.IsSliceMember([]string{utils.DIRECTION, utils.META_DEFAULT, ""}, fieldName) { - return cdr.Direction - } - if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value - return fieldName[len(utils.STATIC_VALUE_PREFIX):] - } - return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) -} func (cdr *CDR) GetSubject(fieldName string) string { if utils.IsSliceMember([]string{utils.SUBJECT, utils.META_DEFAULT, ""}, fieldName) { return cdr.Subject @@ -631,30 +549,6 @@ func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { } return utils.ParseDurationWithSecs(durVal) } -func (cdr *CDR) GetPdd(fieldName string) (time.Duration, error) { - if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT, ""}, fieldName) { - return cdr.PDD, nil - } - var PDDVal string - if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value - PDDVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] - } else { - PDDVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) - } - return utils.ParseDurationWithSecs(PDDVal) -} -func (cdr *CDR) GetSupplier(fieldName string) string { - if utils.IsSliceMember([]string{utils.SUPPLIER, utils.META_DEFAULT, ""}, fieldName) { - return cdr.Supplier - } - return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) -} -func (cdr *CDR) GetDisconnectCause(fieldName string) string { - if utils.IsSliceMember([]string{utils.DISCONNECT_CAUSE, utils.META_DEFAULT, ""}, fieldName) { - return cdr.DisconnectCause - } - return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) -} func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { return cdr.OriginHost @@ -807,18 +701,14 @@ func (cdr *CDR) AsMapStringIface() (mp map[string]interface{}, err error) { mp[utils.ACCID] = cdr.OriginID mp[utils.TOR] = cdr.ToR mp[utils.REQTYPE] = cdr.RequestType - mp[utils.DIRECTION] = cdr.Direction mp[utils.TENANT] = cdr.Tenant mp[utils.CATEGORY] = cdr.Category mp[utils.ACCOUNT] = cdr.Account mp[utils.SUBJECT] = cdr.Subject mp[utils.DESTINATION] = cdr.Destination mp[utils.SETUP_TIME] = cdr.SetupTime - mp[utils.PDD] = cdr.PDD mp[utils.ANSWER_TIME] = cdr.AnswerTime mp[utils.USAGE] = cdr.Usage - mp[utils.SUPPLIER] = cdr.Supplier - mp[utils.DISCONNECT_CAUSE] = cdr.DisconnectCause mp[utils.CostSource] = cdr.CostSource mp[utils.COST] = cdr.Cost mp[utils.COST_DETAILS] = cdr.CostDetails @@ -868,40 +758,97 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck return } +// AsCDRsTBL converts the CDR into the format used for SQL storage +func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { + cdrSql = new(CDRsql) + cdrSql.CGRID = cdr.CGRID + cdrSql.RunID = cdr.RunID + cdrSql.OriginHost = cdr.OriginHost + cdrSql.Source = cdr.Source + cdrSql.OriginID = cdr.OriginID + cdrSql.TOR = cdr.ToR + cdrSql.RequestType = cdr.RequestType + cdrSql.Tenant = cdr.Tenant + cdrSql.Category = cdr.Category + cdrSql.Account = cdr.Account + cdrSql.Subject = cdr.Subject + cdrSql.Destination = cdr.Destination + cdrSql.SetupTime = cdr.SetupTime + cdrSql.AnswerTime = cdr.AnswerTime + cdrSql.Usage = cdr.Usage.Nanoseconds() + cdrSql.ExtraFields = utils.ToJSON(cdr.ExtraFields) + cdrSql.CostSource = cdr.CostSource + cdrSql.Cost = cdr.Cost + cdrSql.CostDetails = utils.ToJSON(cdr.CostDetails) + cdrSql.ExtraInfo = cdr.ExtraInfo + cdrSql.CreatedAt = time.Now() + return +} + +// NewCDRFromSQL converts the CDRsql into CDR +func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { + cdr = new(CDR) + cdr.CGRID = cdrSql.CGRID + cdr.RunID = cdrSql.RunID + cdr.OriginHost = cdrSql.OriginHost + cdr.Source = cdrSql.Source + cdr.OriginID = cdrSql.OriginID + cdr.ToR = cdrSql.TOR + cdr.RequestType = cdrSql.RequestType + cdr.Tenant = cdrSql.Tenant + cdr.Category = cdrSql.Category + cdr.Account = cdrSql.Account + cdr.Subject = cdrSql.Subject + cdr.Destination = cdrSql.Destination + cdr.SetupTime = cdrSql.SetupTime + cdr.AnswerTime = cdrSql.AnswerTime + cdr.Usage = time.Duration(cdrSql.Usage) + + cdr.CostSource = cdrSql.CostSource + cdr.Cost = cdrSql.Cost + cdr.ExtraInfo = cdrSql.ExtraInfo + if cdrSql.ExtraFields != "" { + if err = json.Unmarshal([]byte(cdrSql.ExtraFields), &cdr.ExtraFields); err != nil { + return nil, err + } + } + if cdrSql.CostDetails != "" { + if err = json.Unmarshal([]byte(cdrSql.CostDetails), cdr.CostDetails); err != nil { + return nil, err + } + } + return +} + type ExternalCDR struct { - CGRID string - RunID string - OrderID int64 - OriginHost string - Source string - OriginID string - ToR string - RequestType string - Direction string - Tenant string - Category string - Account string - Subject string - Destination string - SetupTime string - PDD string - AnswerTime string - Usage string - Supplier string - DisconnectCause string - ExtraFields map[string]string - CostSource string - Cost float64 - CostDetails string - ExtraInfo string - Rated bool // Mark the CDR as rated so we do not process it during mediation + CGRID string + RunID string + OrderID int64 + OriginHost string + Source string + OriginID string + ToR string + RequestType string + Tenant string + Category string + Account string + Subject string + Destination string + SetupTime string + AnswerTime string + Usage string + ExtraFields map[string]string + CostSource string + Cost float64 + CostDetails string + ExtraInfo string + Rated bool // Mark the CDR as rated so we do not process it during mediation } // Used when authorizing requests from outside, eg ApierV1.GetMaxUsage type UsageRecord struct { ToR string RequestType string - Direction string Tenant string Category string Account string @@ -915,8 +862,8 @@ type UsageRecord struct { func (self *UsageRecord) AsStoredCdr(timezone string) (*CDR, error) { var err error - cdr := &CDR{CGRID: self.GetId(), ToR: self.ToR, RequestType: self.RequestType, Direction: self.Direction, - Tenant: self.Tenant, Category: self.Category, Account: self.Account, Subject: self.Subject, Destination: self.Destination} + cdr := &CDR{CGRID: self.GetId(), ToR: self.ToR, RequestType: self.RequestType, Tenant: self.Tenant, + Category: self.Category, Account: self.Account, Subject: self.Subject, Destination: self.Destination} if cdr.SetupTime, err = utils.ParseTimeDetectLayout(self.SetupTime, timezone); err != nil { return nil, err } @@ -940,7 +887,7 @@ func (self *UsageRecord) AsCallDescriptor(timezone string, denyNegative bool) (* cd := &CallDescriptor{ CgrID: self.GetId(), TOR: self.ToR, - Direction: self.Direction, + Direction: utils.OUT, Tenant: self.Tenant, Category: self.Category, Subject: self.Subject, @@ -970,5 +917,5 @@ func (self *UsageRecord) AsCallDescriptor(timezone string, denyNegative bool) (* } func (self *UsageRecord) GetId() string { - return utils.Sha1(self.ToR, self.RequestType, self.Direction, self.Tenant, self.Category, self.Account, self.Subject, self.Destination, self.SetupTime, self.AnswerTime, self.Usage) + return utils.Sha1(self.ToR, self.RequestType, self.Tenant, self.Category, self.Account, self.Subject, self.Destination, self.SetupTime, self.AnswerTime, self.Usage) } diff --git a/engine/cdr_test.go b/engine/cdr_test.go index d76058532..b96ee41b8 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -33,17 +33,24 @@ func TestCDRInterfaces(t *testing.T) { } func TestNewCDRFromExternalCDR(t *testing.T) { - extCdr := &ExternalCDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", + extCdr := &ExternalCDR{ + CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + 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", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, + Usage: "0.00000001", 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()), OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10), PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, + eStorCdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, RunID: utils.DEFAULT_RUNID, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10), Cost: 1.01, Rated: true, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if CDR, err := NewCDRFromExternalCDR(extCdr, ""); err != nil { t.Error(err) @@ -53,11 +60,15 @@ func TestNewCDRFromExternalCDR(t *testing.T) { } func TestCDRClone(t *testing.T) { - storCdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10), PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, + storCdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", + Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Cost: 1.01, Rated: true, } if clnStorCdr := storCdr.Clone(); !reflect.DeepEqual(storCdr, clnStorCdr) { t.Errorf("Expecting: %+v, received: %+v", storCdr, clnStorCdr) @@ -65,13 +76,14 @@ func TestCDRClone(t *testing.T) { } func TestFieldAsString(t *testing.T) { - 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_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + 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_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", + Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, PDD: time.Duration(5) * time.Second, Supplier: "SUPPL1", + Usage: time.Duration(10) * time.Second, Cost: 1.01, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, } if cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CGRID || cdr.FieldAsString(&utils.RSRField{Id: utils.ORDERID}) != "123" || @@ -80,7 +92,6 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.OriginHost || cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.Source || cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.RequestType || - cdr.FieldAsString(&utils.RSRField{Id: utils.DIRECTION}) != cdr.Direction || cdr.FieldAsString(&utils.RSRField{Id: utils.CATEGORY}) != cdr.Category || cdr.FieldAsString(&utils.RSRField{Id: utils.ACCOUNT}) != cdr.Account || cdr.FieldAsString(&utils.RSRField{Id: utils.SUBJECT}) != cdr.Subject || @@ -88,8 +99,6 @@ func TestFieldAsString(t *testing.T) { 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.PDD}) != "5" || - cdr.FieldAsString(&utils.RSRField{Id: utils.SUPPLIER}) != cdr.Supplier || 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"] || @@ -103,7 +112,6 @@ func TestFieldAsString(t *testing.T) { cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.OriginHost, cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.Source, cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.RequestType, - cdr.FieldAsString(&utils.RSRField{Id: utils.DIRECTION}) != cdr.Direction, cdr.FieldAsString(&utils.RSRField{Id: utils.CATEGORY}) != cdr.Category, cdr.FieldAsString(&utils.RSRField{Id: utils.ACCOUNT}) != cdr.Account, cdr.FieldAsString(&utils.RSRField{Id: utils.SUBJECT}) != cdr.Subject, @@ -111,8 +119,6 @@ func TestFieldAsString(t *testing.T) { 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.PDD}) != "5", - cdr.FieldAsString(&utils.RSRField{Id: utils.SUPPLIER}) != cdr.Supplier, 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"], @@ -122,15 +128,18 @@ func TestFieldAsString(t *testing.T) { } func TestFieldsAsString(t *testing.T) { - 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_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, PDD: time.Duration(5) * time.Second, Supplier: "SUPPL1", + 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_RATED, Tenant: "cgrates.org", + Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } eVal := "call_from_1001" - if val := cdr.FieldsAsString(utils.ParseRSRFieldsMustCompile("Category;^_from_;Account", utils.INFIELD_SEP)); val != eVal { + if val := cdr.FieldsAsString( + utils.ParseRSRFieldsMustCompile("Category;^_from_;Account", utils.INFIELD_SEP)); val != eVal { t.Errorf("Expecting : %s, received: %s", eVal, val) } } @@ -265,40 +274,47 @@ func TestCDRAsHttpForm(t *testing.T) { */ func TestCDRForkCdr(t *testing.T) { - storCdr := 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: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), PDD: time.Duration(200) * time.Millisecond, - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, Supplier: "suppl1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}, Cost: 1.01} - rtSampleCdrOut, err := storCdr.ForkCdr("sample_run1", &utils.RSRField{Id: utils.REQTYPE}, &utils.RSRField{Id: utils.DIRECTION}, &utils.RSRField{Id: utils.TENANT}, + storCdr := 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: utils.UNIT_TEST, + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", RunID: utils.DEFAULT_RUNID, + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}} + rtSampleCdrOut, err := storCdr.ForkCdr("sample_run1", &utils.RSRField{Id: utils.REQTYPE}, &utils.RSRField{Id: utils.TENANT}, &utils.RSRField{Id: utils.CATEGORY}, &utils.RSRField{Id: utils.ACCOUNT}, &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION}, - &utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.PDD}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, - &utils.RSRField{Id: utils.SUPPLIER}, &utils.RSRField{Id: utils.DISCONNECT_CAUSE}, &utils.RSRField{Id: utils.RATED_FLD}, &utils.RSRField{Id: utils.COST}, + &utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, + &utils.RSRField{Id: utils.RATED_FLD}, &utils.RSRField{Id: utils.COST}, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "field_extr2"}}, true, "") if err != nil { t.Error("Unexpected error received", err) } - expctSplRatedCdr := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), PDD: time.Duration(200) * time.Millisecond, AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(10) * time.Second, Supplier: "suppl1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}, - RunID: "sample_run1", Rated: false, Cost: 1.01} + expctSplRatedCdr := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", + OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}, + RunID: "sample_run1", Rated: false, Cost: 1.01} if !reflect.DeepEqual(expctSplRatedCdr, rtSampleCdrOut) { t.Errorf("Expected: %v, received: %v", expctSplRatedCdr, rtSampleCdrOut) } } func TestCDRForkCdrStaticVals(t *testing.T) { - storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", + storCdr := CDR{ + CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", + OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(10) * time.Second, Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } rsrStPostpaid, _ := utils.NewRSRField("^" + utils.META_POSTPAID) - rsrStIn, _ := utils.NewRSRField("^*in") rsrStCgr, _ := utils.NewRSRField("^cgrates.com") rsrStPC, _ := utils.NewRSRField("^premium_call") rsrStFA, _ := utils.NewRSRField("^first_account") @@ -306,52 +322,55 @@ func TestCDRForkCdrStaticVals(t *testing.T) { rsrStST, _ := utils.NewRSRField("^2013-12-07T08:42:24Z") rsrStAT, _ := utils.NewRSRField("^2013-12-07T08:42:26Z") rsrStDur, _ := utils.NewRSRField("^12s") - rsrStSuppl, _ := utils.NewRSRField("^supplier1") - rsrStDCause, _ := utils.NewRSRField("^HANGUP_COMPLETE") - rsrPDD, _ := utils.NewRSRField("^3") rsrStRated, _ := utils.NewRSRField("^true") rsrStCost, _ := utils.NewRSRField("^1.2") - rtCdrOut2, err := storCdr.ForkCdr("wholesale_run", rsrStPostpaid, rsrStIn, rsrStCgr, rsrStPC, rsrStFA, rsrStFS, &utils.RSRField{Id: utils.DESTINATION}, - rsrStST, rsrPDD, rsrStAT, rsrStDur, rsrStSuppl, rsrStDCause, rsrStRated, rsrStCost, []*utils.RSRField{}, true, "") + rtCdrOut2, err := storCdr.ForkCdr("wholesale_run", rsrStPostpaid, rsrStCgr, rsrStPC, rsrStFA, rsrStFS, &utils.RSRField{Id: utils.DESTINATION}, + rsrStST, rsrStAT, rsrStDur, rsrStRated, rsrStCost, []*utils.RSRField{}, true, "") if err != nil { t.Error("Unexpected error received", err) } - expctRatedCdr2 := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, - Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002", + expctRatedCdr2 := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", + OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, + Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", + Subject: "first_subject", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), - AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(12) * time.Second, PDD: time.Duration(3) * time.Second, - Supplier: "supplier1", DisconnectCause: "HANGUP_COMPLETE", Rated: true, Cost: 1.2, + AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(12) * time.Second, Rated: true, Cost: 1.2, ExtraFields: map[string]string{}, RunID: "wholesale_run"} if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) { t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2) } - _, err = storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: "dummy_header"}, &utils.RSRField{Id: utils.DIRECTION}, &utils.RSRField{Id: utils.TENANT}, - &utils.RSRField{Id: utils.TOR}, &utils.RSRField{Id: utils.ACCOUNT}, &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION}, - &utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.PDD}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, - &utils.RSRField{Id: utils.SUPPLIER}, - &utils.RSRField{Id: utils.DISCONNECT_CAUSE}, &utils.RSRField{Id: utils.RATED_FLD}, &utils.RSRField{Id: utils.COST}, []*utils.RSRField{}, true, "") + _, err = storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: "dummy_header"}, + &utils.RSRField{Id: utils.TENANT}, &utils.RSRField{Id: utils.TOR}, &utils.RSRField{Id: utils.ACCOUNT}, + &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION}, + &utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, + &utils.RSRField{Id: utils.RATED_FLD}, &utils.RSRField{Id: utils.COST}, []*utils.RSRField{}, true, "") if err == nil { t.Error("Failed to detect missing header") } } func TestCDRForkCdrFromMetaDefaults(t *testing.T) { - storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, PDD: time.Duration(4) * time.Second, Supplier: "SUPPL3", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, + storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", + Account: "1001", Subject: "1001", Destination: "1002", RunID: utils.DEFAULT_RUNID, + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } - expctCdr := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(10) * time.Second, PDD: time.Duration(4) * time.Second, Supplier: "SUPPL3", Cost: 1.01, - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: "wholesale_run"} - cdrOut, err := storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, - &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, - &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, - &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, + expctCdr := &CDR{CGRID: storCdr.CGRID, ToR: utils.VOICE, OriginID: "dsafdsaf", + OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, Cost: 1.01, RunID: "wholesale_run", + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} + cdrOut, err := storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, + &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, + &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, + &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true, "") if err != nil { t.Fatal("Unexpected error received", err) @@ -361,7 +380,7 @@ func TestCDRForkCdrFromMetaDefaults(t *testing.T) { t.Errorf("Expected: %v, received: %v", expctCdr, cdrOut) } // Should also accept nil as defaults - if cdrOut, err := storCdr.ForkCdr("wholesale_run", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + if cdrOut, err := storCdr.ForkCdr("wholesale_run", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true, ""); err != nil { t.Fatal("Unexpected error received", err) } else if !reflect.DeepEqual(expctCdr, cdrOut) { @@ -370,28 +389,35 @@ func TestCDRForkCdrFromMetaDefaults(t *testing.T) { } func TestCDRAsExternalCDR(t *testing.T) { - storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", + storCdr := CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10), PDD: time.Duration(7) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01} - expectOutCdr := &ExternalCDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} + expectOutCdr := &ExternalCDR{ + CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + 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", PDD: "7", Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, CostDetails: "null"} + Usage: "0.00000001", Cost: 1.01, CostDetails: "null", + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) } } func TestCDREventFields(t *testing.T) { - 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_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dans", - Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 27, 0, time.UTC), - RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, Supplier: "suppl1", + 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_RATED, Tenant: "cgrates.org", + Category: "call", Account: "dan", Subject: "dans", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 27, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01} if ev := cdr.AsEvent(""); ev != Event(cdr) { @@ -406,9 +432,6 @@ func TestCDREventFields(t *testing.T) { if res := cdr.GetUUID(); res != "dsafdsaf" { t.Error("Received: ", res) } - if res := cdr.GetDirection(utils.META_DEFAULT); res != "*out" { - t.Error("Received: ", res) - } if res := cdr.GetSubject(utils.META_DEFAULT); res != "dans" { t.Error("Received: ", res) } @@ -442,9 +465,6 @@ func TestCDREventFields(t *testing.T) { if dur, _ := cdr.GetDuration(utils.META_DEFAULT); dur != cdr.Usage { t.Error("Received: ", dur) } - if suppl := cdr.GetSupplier(utils.META_DEFAULT); suppl != cdr.Supplier { - t.Error("Received: ", suppl) - } if res := cdr.GetOriginatorIP(utils.META_DEFAULT); res != cdr.OriginHost { t.Error("Received: ", res) } @@ -454,13 +474,17 @@ func TestCDREventFields(t *testing.T) { } func TesUsageReqAsCDR(t *testing.T) { - setupReq := &UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + setupReq := &UsageRecord{ToR: utils.VOICE, 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", Usage: "0.00000001", - } - eStorCdr := &CDR{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10)} + SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", + Usage: "0.00000001"} + eStorCdr := &CDR{ToR: utils.VOICE, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10)} if CDR, err := setupReq.AsStoredCdr(""); err != nil { t.Error(err) } else if !reflect.DeepEqual(eStorCdr, CDR) { @@ -469,13 +493,19 @@ func TesUsageReqAsCDR(t *testing.T) { } func TestUsageReqAsCD(t *testing.T) { - req := &UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + req := &UsageRecord{ToR: utils.VOICE, 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", Usage: "0.00000001", + SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", + Usage: "0.00000001", } - eCD := &CallDescriptor{CgrID: "9473e7b2e075d168b9da10ae957ee68fe5a217e4", TOR: req.ToR, Direction: req.Direction, Tenant: req.Tenant, - Category: req.Category, Account: req.Account, Subject: req.Subject, Destination: req.Destination, - TimeStart: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), TimeEnd: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Add(time.Duration(10)), DenyNegativeAccount: true} + eCD := &CallDescriptor{CgrID: "48ca1a2eb82b028fbfc809e36a585061a775ffc3", TOR: req.ToR, + Direction: utils.OUT, Tenant: req.Tenant, + Category: req.Category, Account: req.Account, + Subject: req.Subject, Destination: req.Destination, + TimeStart: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + TimeEnd: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Add(time.Duration(10)), + DenyNegativeAccount: true} if cd, err := req.AsCallDescriptor("", true); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCD, cd) { @@ -511,7 +541,6 @@ func TestCDRAsMapStringIface(t *testing.T) { OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1002", @@ -521,40 +550,35 @@ func TestCDRAsMapStringIface(t *testing.T) { AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, - Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } mp := map[string]interface{}{ - "field_extr1": "val_extr1", - "fieldextr2": "valextr2", - utils.CGRID: cdr.CGRID, - utils.MEDI_RUNID: utils.DEFAULT_RUNID, - utils.ORDERID: cdr.OrderID, - utils.CDRHOST: "192.168.1.1", - utils.CDRSOURCE: utils.UNIT_TEST, - utils.ACCID: "dsafdsaf", - utils.TOR: utils.VOICE, - utils.REQTYPE: utils.META_RATED, - utils.DIRECTION: "*out", - utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", - utils.ACCOUNT: "1002", - utils.SUBJECT: "1001", - utils.DESTINATION: "+4986517174963", - utils.SETUP_TIME: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - utils.PDD: time.Duration(0) * time.Second, - utils.ANSWER_TIME: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - utils.USAGE: time.Duration(10) * time.Second, - utils.SUPPLIER: "SUPPL1", - utils.DISCONNECT_CAUSE: cdr.DisconnectCause, - utils.CostSource: cdr.CostSource, - utils.COST: 1.01, - utils.COST_DETAILS: cdr.CostDetails, - utils.RATED: false, - utils.PartialField: false, - utils.ExtraInfo: cdr.ExtraInfo, + "field_extr1": "val_extr1", + "fieldextr2": "valextr2", + utils.CGRID: cdr.CGRID, + utils.MEDI_RUNID: utils.DEFAULT_RUNID, + utils.ORDERID: cdr.OrderID, + utils.CDRHOST: "192.168.1.1", + utils.CDRSOURCE: utils.UNIT_TEST, + utils.ACCID: "dsafdsaf", + utils.TOR: utils.VOICE, + utils.REQTYPE: utils.META_RATED, + utils.TENANT: "cgrates.org", + utils.CATEGORY: "call", + utils.ACCOUNT: "1002", + utils.SUBJECT: "1001", + utils.DESTINATION: "+4986517174963", + utils.SETUP_TIME: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + utils.ANSWER_TIME: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + utils.USAGE: time.Duration(10) * time.Second, + utils.CostSource: cdr.CostSource, + utils.COST: 1.01, + utils.COST_DETAILS: cdr.CostDetails, + utils.RATED: false, + utils.PartialField: false, + utils.ExtraInfo: cdr.ExtraInfo, } if cdrMp, err := cdr.AsMapStringIface(); err != nil { t.Error(err) @@ -571,7 +595,7 @@ func TestCDRAsExportRecord(t *testing.T) { ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", @@ -635,12 +659,15 @@ func TestCDRAsExportRecord(t *testing.T) { } func TestCDRAsExportMap(t *testing.T) { - 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: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, + 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: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "+4986517174963", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(10) * time.Second, Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } eCDRMp := map[string]string{ utils.CGRID: cdr.CGRID, diff --git a/engine/cdrecsv_test.go b/engine/cdrecsv_test.go index 2b1ec84ba..1158a7dcf 100644 --- a/engine/cdrecsv_test.go +++ b/engine/cdrecsv_test.go @@ -32,11 +32,14 @@ func TestCsvCdrWriter(t *testing.T) { writer := &bytes.Buffer{} cfg, _ := config.NewDefaultCGRConfig() storedCdr1 := &CDR{ - CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), - Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, - ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01, + CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), + ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", + Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Unix(1383813745, 0).UTC(), + AnswerTime: time.Unix(1383813746, 0).UTC(), + Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 1.01, + ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, } cdre, err := NewCDRExporter([]*CDR{storedCdr1}, cfg.CdreProfiles["*default"], utils.MetaFileCSV, "", "", "firstexport", true, 1, ',', map[string]float64{}, 0.0, cfg.RoundingDecimals, cfg.HttpSkipTlsVerify, nil) @@ -50,7 +53,7 @@ func TestCsvCdrWriter(t *testing.T) { if err := cdre.writeCsv(csvWriter); err != nil { t.Error("Unexpected error: ", err) } - expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,*default,*voice,dsafdsaf,*rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07T08:42:25Z,2013-11-07T08:42:26Z,10,1.01000` + expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,*default,*voice,dsafdsaf,*rated,cgrates.org,call,1001,1001,1002,2013-11-07T08:42:25Z,2013-11-07T08:42:26Z,10,1.01000` result := strings.TrimSpace(writer.String()) if result != expected { t.Errorf("Expected: \n%s received: \n%s.", expected, result) @@ -63,11 +66,15 @@ func TestCsvCdrWriter(t *testing.T) { func TestAlternativeFieldSeparator(t *testing.T) { writer := &bytes.Buffer{} cfg, _ := config.NewDefaultCGRConfig() - storedCdr1 := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), - Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, - ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01, + storedCdr1 := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), + ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", + Account: "1001", Subject: "1001", Destination: "1002", + SetupTime: time.Unix(1383813745, 0).UTC(), + AnswerTime: time.Unix(1383813746, 0).UTC(), + Usage: time.Duration(10) * time.Second, + RunID: utils.DEFAULT_RUNID, Cost: 1.01, + ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, } cdre, err := NewCDRExporter([]*CDR{storedCdr1}, cfg.CdreProfiles["*default"], utils.MetaFileCSV, "", "", "firstexport", true, 1, '|', map[string]float64{}, 0.0, cfg.RoundingDecimals, cfg.HttpSkipTlsVerify, nil) @@ -81,7 +88,7 @@ func TestAlternativeFieldSeparator(t *testing.T) { if err := cdre.writeCsv(csvWriter); err != nil { t.Error("Unexpected error: ", err) } - expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6|*default|*voice|dsafdsaf|*rated|*out|cgrates.org|call|1001|1001|1002|2013-11-07T08:42:25Z|2013-11-07T08:42:26Z|10|1.01000` + expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6|*default|*voice|dsafdsaf|*rated|cgrates.org|call|1001|1001|1002|2013-11-07T08:42:25Z|2013-11-07T08:42:26Z|10|1.01000` result := strings.TrimSpace(writer.String()) if result != expected { t.Errorf("Expected: \n%s received: \n%s.", expected, result) diff --git a/engine/cdrefwv_test.go b/engine/cdrefwv_test.go index 9a52e878b..4c29f3065 100644 --- a/engine/cdrefwv_test.go +++ b/engine/cdrefwv_test.go @@ -28,28 +28,45 @@ import ( ) var hdrJsnCfgFlds = []*config.CdrFieldJsonCfg{ - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("10"), Width: utils.IntPointer(2)}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.META_FILLER), Width: utils.IntPointer(3)}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("VOI"), Width: utils.IntPointer(3)}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_EXPORTID), - Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdr"), Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_LASTCDRATIME), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), + Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("10"), + Width: utils.IntPointer(2)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), + Type: utils.StringPointer(utils.META_FILLER), Width: utils.IntPointer(3)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), + Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("VOI"), + Width: utils.IntPointer(3)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), + Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_EXPORTID), + Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), + Padding: utils.StringPointer("zeroleft")}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdr"), + Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_LASTCDRATIME), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileCreationfTime"), Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_TIMENOW), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileCreationfTime"), + Type: utils.StringPointer(utils.META_HANDLER), Value: utils.StringPointer(META_TIMENOW), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileVersion"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("01"), Width: utils.IntPointer(2)}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.META_FILLER), Width: utils.IntPointer(105)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileVersion"), + Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("01"), + Width: utils.IntPointer(2)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), + Type: utils.StringPointer(utils.META_FILLER), Width: utils.IntPointer(105)}, } var contentJsnCfgFlds = []*config.CdrFieldJsonCfg{ - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("20"), Width: utils.IntPointer(2)}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ACCOUNT), Width: utils.IntPointer(12), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), + Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("20"), Width: utils.IntPointer(2)}, + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.ACCOUNT), Width: utils.IntPointer(12), Strip: utils.StringPointer("left"), Padding: utils.StringPointer("right")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.SUBJECT), Width: utils.IntPointer(5), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.SUBJECT), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("CLI"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("cli"), Width: utils.IntPointer(15), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("CLI"), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("cli"), Width: utils.IntPointer(15), Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")}, - &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.DESTINATION), Width: utils.IntPointer(24), + &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.DESTINATION), Width: utils.IntPointer(24), Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")}, &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("02"), Width: utils.IntPointer(2)}, &config.CdrFieldJsonCfg{Tag: utils.StringPointer("SubtypeTOR"), Type: utils.StringPointer(utils.META_CONSTANT), Value: utils.StringPointer("11"), Width: utils.IntPointer(4), @@ -117,11 +134,12 @@ func TestWriteCdr(t *testing.T) { } cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), ToR: utils.VOICE, OrderID: 1, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", - Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", + Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 2.34567, + Usage: time.Duration(10) * time.Second, + RunID: utils.DEFAULT_RUNID, Cost: 2.34567, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } @@ -178,7 +196,8 @@ func TestWriteCdrs(t *testing.T) { TrailerFields: trailerCfgFlds, } cdr1 := &CDR{CGRID: utils.Sha1("aaa1", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), - ToR: utils.VOICE, OrderID: 2, OriginID: "aaa1", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + ToR: utils.VOICE, OrderID: 2, OriginID: "aaa1", OriginHost: "192.168.1.1", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1010", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), @@ -186,20 +205,24 @@ func TestWriteCdrs(t *testing.T) { ExtraFields: map[string]string{"productnumber": "12341", "fieldextr2": "valextr2"}, } cdr2 := &CDR{CGRID: utils.Sha1("aaa2", time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC).String()), - ToR: utils.VOICE, OrderID: 4, OriginID: "aaa2", OriginHost: "192.168.1.2", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + ToR: utils.VOICE, OrderID: 4, OriginID: "aaa2", OriginHost: "192.168.1.2", + RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1011", SetupTime: time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 7, 42, 26, 0, time.UTC), - Usage: time.Duration(5) * time.Minute, RunID: utils.DEFAULT_RUNID, Cost: 1.40001, + Usage: time.Duration(5) * time.Minute, + RunID: utils.DEFAULT_RUNID, Cost: 1.40001, ExtraFields: map[string]string{"productnumber": "12342", "fieldextr2": "valextr2"}, } cdr3 := &CDR{} cdr4 := &CDR{CGRID: utils.Sha1("aaa3", time.Date(2013, 11, 7, 9, 42, 18, 0, time.UTC).String()), - ToR: utils.VOICE, OrderID: 3, OriginID: "aaa4", OriginHost: "192.168.1.4", RequestType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + ToR: utils.VOICE, OrderID: 3, OriginID: "aaa4", OriginHost: "192.168.1.4", + RequestType: utils.META_POSTPAID, Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1013", SetupTime: time.Date(2013, 11, 7, 9, 42, 18, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 9, 42, 26, 0, time.UTC), - Usage: time.Duration(20) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 2.34567, + Usage: time.Duration(20) * time.Second, + RunID: utils.DEFAULT_RUNID, Cost: 2.34567, ExtraFields: map[string]string{"productnumber": "12344", "fieldextr2": "valextr2"}, } cfg, _ := config.NewDefaultCGRConfig() diff --git a/engine/cdrs.go b/engine/cdrs.go index 953160bee..1b3ba3864 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -166,9 +166,6 @@ func (self *CdrServer) storeSMCost(smCost *SMCost, checkDuplicate bool) error { // Returns error if not able to properly store the CDR, mediation is async since we can always recover offline func (self *CdrServer) processCdr(cdr *CDR) (err error) { - if cdr.Direction == "" { - cdr.Direction = utils.OUT - } if cdr.RequestType == "" { cdr.RequestType = self.cgrCfg.DefaultReqType } @@ -248,7 +245,7 @@ func (self *CdrServer) deriveRateStoreStatsReplicate(cdr *CDR, store, cdrstats, } if err := LoadAlias(&AttrMatchingAlias{ Destination: cdrRun.Destination, - Direction: cdrRun.Direction, + Direction: utils.OUT, Tenant: cdrRun.Tenant, Category: cdrRun.Category, Account: cdrRun.Account, @@ -275,21 +272,6 @@ func (self *CdrServer) deriveRateStoreStatsReplicate(cdr *CDR, store, cdrstats, } } } - // Store AccountSummary if requested - if self.cgrCfg.CDRScdrAccountSummary { - for _, ratedCDR := range ratedCDRs { - if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID, utils.META_PSEUDOPREPAID, utils.PSEUDOPREPAID, - utils.META_POSTPAID, utils.POSTPAID}, ratedCDR.RequestType) { - acntID := utils.ConcatenatedKey(ratedCDR.Tenant, ratedCDR.Account) - acnt, err := self.dm.DataDB().GetAccount(acntID) - if err != nil { - utils.Logger.Err(fmt.Sprintf(" Querying AccountDigest for account: %s got error: %s", acntID, err.Error())) - } else if acnt.ID != "" { - ratedCDR.AccountSummary = acnt.AsAccountSummary() - } - } - } - } // Store rated CDRs if store { for _, ratedCDR := range ratedCDRs { @@ -340,7 +322,7 @@ func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { } if err := LoadAlias(&AttrMatchingAlias{ Destination: cdr.Destination, - Direction: cdr.Direction, + Direction: utils.OUT, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, @@ -349,7 +331,7 @@ func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return nil, err } - attrsDC := &utils.AttrDerivedChargers{Tenant: cdr.Tenant, Category: cdr.Category, Direction: cdr.Direction, + attrsDC := &utils.AttrDerivedChargers{Tenant: cdr.Tenant, Category: cdr.Category, Direction: utils.OUT, Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination} var dcs utils.DerivedChargers if err := self.rals.Call("Responder.GetDerivedChargers", attrsDC, &dcs); err != nil { @@ -369,18 +351,14 @@ func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { continue } dcRequestTypeFld, _ := utils.NewRSRField(dc.RequestTypeField) - dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) - dcPddFld, _ := utils.NewRSRField(dc.PDDField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) - dcSupplFld, _ := utils.NewRSRField(dc.SupplierField) - dcDCauseFld, _ := utils.NewRSRField(dc.DisconnectCauseField) dcRatedFld, _ := utils.NewRSRField(dc.RatedField) dcCostFld, _ := utils.NewRSRField(dc.CostField) @@ -389,8 +367,8 @@ func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { dcExtraFields = append(dcExtraFields, &utils.RSRField{Id: key}) } - forkedCdr, err := cdr.ForkCdr(dc.RunID, dcRequestTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, - dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, dcExtraFields, true, self.cgrCfg.DefaultTimezone) + forkedCdr, err := cdr.ForkCdr(dc.RunID, dcRequestTypeFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, + dcSTimeFld, dcATimeFld, dcDurFld, dcRatedFld, dcCostFld, dcExtraFields, true, self.cgrCfg.DefaultTimezone) if err != nil { utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", cdr.CGRID, dc.RunID, err.Error())) continue // do not add it to the forked CDR list @@ -470,7 +448,7 @@ func (self *CdrServer) getCostFromRater(cdr *CDR) (*CallCost, error) { } cd := &CallDescriptor{ TOR: cdr.ToR, - Direction: cdr.Direction, + Direction: utils.OUT, Tenant: cdr.Tenant, Category: cdr.Category, Subject: cdr.Subject, diff --git a/engine/cdrstats.go b/engine/cdrstats.go index 842ed2a48..ffaf57236 100644 --- a/engine/cdrstats.go +++ b/engine/cdrstats.go @@ -105,9 +105,6 @@ func (cs *CdrStats) AcceptCdr(cdr *CDR) bool { if len(cs.ReqType) > 0 && !utils.IsSliceMember(cs.ReqType, cdr.RequestType) { return false } - if len(cs.Direction) > 0 && !utils.IsSliceMember(cs.Direction, cdr.Direction) { - return false - } if len(cs.Tenant) > 0 && !utils.IsSliceMember(cs.Tenant, cdr.Tenant) { return false } @@ -150,20 +147,6 @@ func (cs *CdrStats) AcceptCdr(cdr *CDR) bool { return false } } - if len(cs.PddInterval) > 0 { - if cdr.PDD < cs.PddInterval[0] { - return false - } - if len(cs.PddInterval) > 1 && cdr.PDD >= cs.PddInterval[1] { - return false - } - } - if len(cs.Supplier) > 0 && !utils.IsSliceMember(cs.Supplier, cdr.Supplier) { - return false - } - if len(cs.DisconnectCause) > 0 && !utils.IsSliceMember(cs.DisconnectCause, cdr.DisconnectCause) { - return false - } if len(cs.MediationRunIds) > 0 && !utils.IsSliceMember(cs.MediationRunIds, cdr.RunID) { return false } diff --git a/engine/cdrstats_queue.go b/engine/cdrstats_queue.go index 20a9a6711..d1150e67a 100644 --- a/engine/cdrstats_queue.go +++ b/engine/cdrstats_queue.go @@ -201,7 +201,6 @@ func (sq *CDRStatsQueue) simplifyCdr(cdr *CDR) *QCdr { return &QCdr{ SetupTime: cdr.SetupTime, AnswerTime: cdr.AnswerTime, - Pdd: cdr.PDD, Usage: cdr.Usage, Cost: cdr.Cost, Dest: cdr.Destination, diff --git a/engine/cgrcdr.go b/engine/cgrcdr.go index 54e0af8e6..de3cbe296 100644 --- a/engine/cgrcdr.go +++ b/engine/cgrcdr.go @@ -66,18 +66,14 @@ func (cgrCdr CgrCdr) AsStoredCdr(timezone string) *CDR { storCdr.OriginHost = cgrCdr[utils.CDRHOST] storCdr.Source = cgrCdr[utils.CDRSOURCE] storCdr.RequestType = cgrCdr[utils.REQTYPE] - storCdr.Direction = utils.OUT storCdr.Tenant = cgrCdr[utils.TENANT] storCdr.Category = cgrCdr[utils.CATEGORY] storCdr.Account = cgrCdr[utils.ACCOUNT] storCdr.Subject = cgrCdr[utils.SUBJECT] 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.PDD, _ = utils.ParseDurationWithSecs(cgrCdr[utils.PDD]) storCdr.AnswerTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.ANSWER_TIME], timezone) storCdr.Usage, _ = utils.ParseDurationWithSecs(cgrCdr[utils.USAGE]) - storCdr.Supplier = cgrCdr[utils.SUPPLIER] - storCdr.DisconnectCause = cgrCdr[utils.DISCONNECT_CAUSE] 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 bcf267b12..b020ca2e8 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -33,19 +33,25 @@ func TestCgrCdrInterfaces(t *testing.T) { } func TestCgrCdrAsCDR(t *testing.T) { - cgrCdr := CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "dsafdsaf", utils.CDRHOST: "192.168.1.1", 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.ANSWER_TIME: "2013-11-07T08:42:26Z", - utils.USAGE: "10", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} + cgrCdr := CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "dsafdsaf", utils.CDRHOST: "192.168.1.1", + utils.CDRSOURCE: "internal_test", utils.REQTYPE: utils.META_RATED, + 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"} setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") - expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], OriginHost: cgrCdr[utils.CDRHOST], + expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), + ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], + OriginHost: cgrCdr[utils.CDRHOST], Source: cgrCdr[utils.CDRSOURCE], RequestType: cgrCdr[utils.REQTYPE], - Direction: cgrCdr[utils.DIRECTION], Tenant: cgrCdr[utils.TENANT], Category: cgrCdr[utils.CATEGORY], Account: cgrCdr[utils.ACCOUNT], Subject: cgrCdr[utils.SUBJECT], - Destination: cgrCdr[utils.DESTINATION], SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: -1} + Tenant: cgrCdr[utils.TENANT], Category: cgrCdr[utils.CATEGORY], + Account: cgrCdr[utils.ACCOUNT], Subject: cgrCdr[utils.SUBJECT], + Destination: cgrCdr[utils.DESTINATION], + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, Cost: -1, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if CDR := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, CDR) { t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR) } @@ -59,26 +65,21 @@ func TestReplicatedCgrCdrAsCDR(t *testing.T) { 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"} expctRtCdr := &CDR{CGRID: cgrCdr[utils.CGRID], - ToR: cgrCdr[utils.TOR], - OriginID: cgrCdr[utils.ACCID], - OriginHost: cgrCdr[utils.CDRHOST], - Source: cgrCdr[utils.CDRSOURCE], - RequestType: cgrCdr[utils.REQTYPE], - Direction: cgrCdr[utils.DIRECTION], - Tenant: cgrCdr[utils.TENANT], - Category: cgrCdr[utils.CATEGORY], - Account: cgrCdr[utils.ACCOUNT], - Subject: cgrCdr[utils.SUBJECT], - Destination: cgrCdr[utils.DESTINATION], - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - PDD: time.Duration(200) * time.Millisecond, - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(10) * time.Second, - Supplier: cgrCdr[utils.SUPPLIER], - DisconnectCause: cgrCdr[utils.DISCONNECT_CAUSE], - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 0.12, - Rated: true, + ToR: cgrCdr[utils.TOR], + OriginID: cgrCdr[utils.ACCID], + OriginHost: cgrCdr[utils.CDRHOST], + Source: cgrCdr[utils.CDRSOURCE], + RequestType: cgrCdr[utils.REQTYPE], + Tenant: cgrCdr[utils.TENANT], + Category: cgrCdr[utils.CATEGORY], + Account: cgrCdr[utils.ACCOUNT], + Subject: cgrCdr[utils.SUBJECT], + Destination: cgrCdr[utils.DESTINATION], + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(10) * time.Second, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Cost: 0.12, Rated: true, } if CDR := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, CDR) { t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR) diff --git a/engine/event.go b/engine/event.go index 1c5ca5ad5..3f1af1eea 100644 --- a/engine/event.go +++ b/engine/event.go @@ -28,7 +28,6 @@ type Event interface { GetCgrId(timezone string) string GetUUID() string GetSessionIds() []string // Returns identifiers needed to control a session (eg disconnect) - GetDirection(string) string GetSubject(string) string GetAccount(string) string GetDestination(string) string @@ -41,9 +40,6 @@ type Event interface { GetAnswerTime(string, string) (time.Time, error) GetEndTime(string, string) (time.Time, error) GetDuration(string) (time.Duration, error) - GetPdd(string) (time.Duration, error) - GetSupplier(string) string - GetDisconnectCause(string) string GetExtraFields() map[string]string MissingParameter(string) bool ParseEventValue(*utils.RSRField, string) string diff --git a/engine/fscdr.go b/engine/fscdr.go index a6aee5816..5f42497a0 100644 --- a/engine/fscdr.go +++ b/engine/fscdr.go @@ -24,7 +24,6 @@ import ( "reflect" "strconv" "strings" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" @@ -131,20 +130,14 @@ func (fsCdr FSCdr) AsStoredCdr(timezone string) *CDR { storCdr.OriginHost = fsCdr.vars[FS_IP] storCdr.Source = FS_CDR_SOURCE storCdr.RequestType = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_REQTYPE], fsCdr.cgrCfg.DefaultReqType) - storCdr.Direction = utils.OUT storCdr.Tenant = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_TENANT], fsCdr.cgrCfg.DefaultTenant) storCdr.Category = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_CATEGORY], fsCdr.cgrCfg.DefaultCategory) storCdr.Account = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_ACCOUNT], fsCdr.vars[FS_USERNAME]) storCdr.Subject = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_SUBJECT], fsCdr.vars[utils.CGR_ACCOUNT], fsCdr.vars[FS_USERNAME]) storCdr.Destination = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_DESTINATION], fsCdr.vars[FS_CALL_DEST_NR], fsCdr.vars[FS_SIP_REQUSER]) storCdr.SetupTime, _ = utils.ParseTimeDetectLayout(fsCdr.vars[FS_SETUP_TIME], timezone) // Not interested to process errors, should do them if necessary in a previous step - pddStr := utils.FirstNonEmpty(fsCdr.vars[FS_PROGRESS_MEDIAMSEC], fsCdr.vars[FS_PROGRESSMS]) - pddStr += "ms" - storCdr.PDD, _ = time.ParseDuration(pddStr) storCdr.AnswerTime, _ = utils.ParseTimeDetectLayout(fsCdr.vars[FS_ANSWER_TIME], timezone) storCdr.Usage, _ = utils.ParseDurationWithSecs(fsCdr.vars[FS_DURATION]) - storCdr.Supplier = fsCdr.vars[utils.CGR_SUPPLIER] - storCdr.DisconnectCause = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_DISCONNECT_CAUSE], fsCdr.vars["hangup_cause"]) storCdr.ExtraFields = fsCdr.getExtraFields() storCdr.Cost = -1 return storCdr diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go index 64c90e303..37dce794b 100644 --- a/engine/fscdr_test.go +++ b/engine/fscdr_test.go @@ -53,10 +53,15 @@ func TestCDRFields(t *testing.T) { } setupTime, _ := utils.ParseTimeDetectLayout("1436280728", "") answerTime, _ := utils.ParseTimeDetectLayout("1436280728", "") - expctCDR := &CDR{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", ToR: utils.VOICE, OriginID: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", - OriginHost: "127.0.0.1", Source: "freeswitch_json", Direction: utils.OUT, Category: "call", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Account: "1001", Subject: "1001", - Destination: "1003", SetupTime: setupTime, PDD: time.Duration(28) * time.Millisecond, AnswerTime: answerTime, Usage: time.Duration(66) * time.Second, Supplier: "supplier1", - DisconnectCause: "NORMAL_CLEARING", ExtraFields: map[string]string{"sip_user_agent": "PJSUA v2.3 Linux-3.2.0.4/x86_64/glibc-2.13"}, Cost: -1} + expctCDR := &CDR{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", + ToR: utils.VOICE, OriginID: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", + OriginHost: "127.0.0.1", Source: "freeswitch_json", Category: "call", + RequestType: utils.META_PREPAID, Tenant: "cgrates.org", + Account: "1001", Subject: "1001", + Destination: "1003", SetupTime: setupTime, + AnswerTime: answerTime, Usage: time.Duration(66) * time.Second, + Cost: -1, + ExtraFields: map[string]string{"sip_user_agent": "PJSUA v2.3 Linux-3.2.0.4/x86_64/glibc-2.13"}} if CDR := fsCdr.AsStoredCdr(""); !reflect.DeepEqual(expctCDR, CDR) { t.Errorf("Expecting: %v, received: %v", expctCDR, CDR) } diff --git a/engine/models.go b/engine/models.go index ded146bd6..b123d13c0 100755 --- a/engine/models.go +++ b/engine/models.go @@ -398,59 +398,6 @@ func (ta *TpAlias) GetId() string { return utils.ConcatenatedKey(ta.Direction, ta.Tenant, ta.Category, ta.Account, ta.Subject, ta.Context) } -type TBLCDRs struct { - ID int64 - Cgrid string - RunID string - OriginHost string - Source string - OriginID string - Tor string - RequestType string - Direction string - Tenant string - Category string - Account string - Subject string - Destination string - SetupTime time.Time - Pdd float64 - AnswerTime time.Time - Usage float64 - Supplier string - DisconnectCause string - ExtraFields string - Cost float64 - CostDetails string - CostSource string - AccountSummary string - ExtraInfo string - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time -} - -func (t TBLCDRs) TableName() string { - return utils.TBLCDRs -} - -type TBLSMCosts struct { - ID int64 - Cgrid string - RunID string - OriginHost string - OriginID string - CostSource string - Usage float64 - CostDetails string - CreatedAt time.Time - DeletedAt *time.Time -} - -func (t TBLSMCosts) TableName() string { - return utils.TBLSMCosts -} - type TpResource struct { PK uint `gorm:"primary_key"` Tpid string @@ -468,16 +415,6 @@ type TpResource struct { CreatedAt time.Time } -type TBLVersion struct { - ID uint - Item string - Version int64 -} - -func (t TBLVersion) TableName() string { - return utils.TBLVersions -} - type TpStats struct { PK uint `gorm:"primary_key"` Tpid string @@ -524,3 +461,61 @@ type TpFilter struct { ActivationInterval string `index:"5" re:""` CreatedAt time.Time } + +type CDRsql struct { + ID int64 + CGRID string + RunID string + OriginHost string + Source string + OriginID string + TOR string + RequestType string + Tenant string + Category string + Account string + Subject string + Destination string + SetupTime time.Time + AnswerTime time.Time + Usage int64 + ExtraFields string + CostSource string + Cost float64 + CostDetails string + ExtraInfo string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time +} + +func (t CDRsql) TableName() string { + return utils.CDRsTBL +} + +type SMCostSQL struct { + ID int64 + Cgrid string + RunID string + OriginHost string + OriginID string + CostSource string + Usage float64 + CostDetails string + CreatedAt time.Time + DeletedAt *time.Time +} + +func (t SMCostSQL) TableName() string { + return utils.SMCostsTBL +} + +type TBLVersion struct { + ID uint + Item string + Version int64 +} + +func (t TBLVersion) TableName() string { + return utils.TBLVersions +} diff --git a/engine/responder.go b/engine/responder.go index a8014a128..c67ee312e 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -302,7 +302,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { if err := LoadAlias( &AttrMatchingAlias{ Destination: ev.Destination, - Direction: ev.Direction, + Direction: utils.OUT, Tenant: ev.Tenant, Category: ev.Category, Account: ev.Account, @@ -314,7 +314,8 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { } maxCallDuration := -1.0 - attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), + attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), + Category: ev.GetCategory(utils.META_DEFAULT), Direction: utils.OUT, Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} dcs := &utils.DerivedChargers{} if err := rs.GetDerivedChargers(attrsDC, dcs); err != nil { @@ -354,7 +355,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { CgrID: ev.GetCgrId(rs.Timezone), RunID: dc.RunID, TOR: ev.ToR, - Direction: ev.GetDirection(dc.DirectionField), + Direction: utils.OUT, Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), @@ -407,7 +408,7 @@ func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error { if err := LoadAlias( &AttrMatchingAlias{ Destination: ev.Destination, - Direction: ev.Direction, + Direction: utils.OUT, Tenant: ev.Tenant, Category: ev.Category, Account: ev.Account, @@ -418,8 +419,10 @@ func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error { } //utils.Logger.Info(fmt.Sprintf("DC after: %+v", ev)) - attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), - Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT), Destination: ev.GetDestination(utils.META_DEFAULT)} + attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), + Category: ev.GetCategory(utils.META_DEFAULT), Direction: utils.OUT, + Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT), + Destination: ev.GetDestination(utils.META_DEFAULT)} //utils.Logger.Info(fmt.Sprintf("Derived chargers for: %+v", attrsDC)) dcs := &utils.DerivedChargers{} if err := rs.GetDerivedChargers(attrsDC, dcs); err != nil { @@ -453,7 +456,7 @@ func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error { CgrID: ev.GetCgrId(rs.Timezone), RunID: dc.RunID, TOR: ev.ToR, - Direction: ev.GetDirection(dc.DirectionField), + Direction: utils.OUT, Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), diff --git a/engine/responder_test.go b/engine/responder_test.go index b865a20b8..567f0f10e 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -55,11 +55,14 @@ func TestResponderGetDerivedChargers(t *testing.T) { func TestResponderGetDerivedMaxSessionTime(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_RATED, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan", Subject: "dan", - Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01} + 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_RATED, Tenant: testTenant, Category: "call", Account: "dan", Subject: "dan", + Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Cost: 1.01} var maxSessionTime float64 if err := rsponder.GetDerivedMaxSessionTime(cdr, &maxSessionTime); err != nil { t.Error(err) @@ -75,8 +78,10 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { } b10 := &Balance{Value: 10, Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} b20 := &Balance{Value: 20, Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} - rifsAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "rif"), BalanceMap: map[string]Balances{utils.VOICE: Balances{b10}}} - dansAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "dan"), BalanceMap: map[string]Balances{utils.VOICE: Balances{b20}}} + rifsAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "rif"), + BalanceMap: map[string]Balances{utils.VOICE: Balances{b10}}} + dansAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "dan"), + BalanceMap: map[string]Balances{utils.VOICE: Balances{b20}}} if err := dm.DataDB().SetAccount(rifsAccount); err != nil { t.Error(err) } @@ -123,11 +128,13 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { 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, + 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, + Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2", + Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + 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, @@ -456,85 +463,98 @@ func TestResponderGetLCR(t *testing.T) { } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) } + /* + // Test *qos_threshold strategy here, + // FixMe with newly stats + cdQosThreshold := &CallDescriptor{ + TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), + TimeEnd: time.Date(2015, 04, 06, 17, 41, 0, 0, time.UTC), + Tenant: "tenant12", + Direction: utils.OUT, + Category: "call_qos_threshold", + Destination: "+4986517174963", + Account: "dan", + Subject: "dan", + } + eQTLcr := &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", + Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, + QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, + QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, + QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + }, + } + var lcrQT LCRCost + if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) - // Test *qos_threshold strategy here - cdQosThreshold := &CallDescriptor{ - TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), - TimeEnd: time.Date(2015, 04, 06, 17, 41, 0, 0, time.UTC), - Tenant: "tenant12", - Direction: utils.OUT, - Category: "call_qos_threshold", - Destination: "+4986517174963", - Account: "dan", - Subject: "dan", - } - eQTLcr := &LCRCost{ - Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, - SupplierCosts: []*LCRSupplierCost{ - &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, PDD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, - }, - } - var lcrQT LCRCost - if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) + } - } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) - } + cdr := &CDR{AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + cdr = &CDR{AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) - cdr := &CDR{Supplier: "rif12", AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} - rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) - cdr = &CDR{Supplier: "dan12", AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} - rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + eQTLcr = &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", + Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}}, + }, + } + if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %s, received: %s", + utils.ToJSON(eQTLcr.SupplierCosts), utils.ToJSON(lcrQT.SupplierCosts)) + } - eQTLcr = &LCRCost{ - Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, - SupplierCosts: []*LCRSupplierCost{ - &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, QOS: map[string]float64{PDD: -1, TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}}, - }, - } - if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) - } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) - } + // Test *qos strategy here + cdQos := &CallDescriptor{ + TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), + TimeEnd: time.Date(2015, 04, 06, 17, 41, 0, 0, time.UTC), + Tenant: "tenant12", + Direction: utils.OUT, + Category: "call_qos", + Destination: "+4986517174963", + Account: "dan", + Subject: "dan", + } + eQosLcr := &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS, Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, + QOS: map[string]float64{ACD: -1, PDD: -1, TCD: -1, ASR: -1, ACC: -1, TCC: -1, DDC: -1}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, + QOS: map[string]float64{ACD: 300, PDD: -1, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, + QOS: map[string]float64{ACD: 180, PDD: -1, TCD: 180, ASR: 100, ACC: 1, TCC: 1, DDC: 1}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, + }, + } + var lcrQ LCRCost + if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQos}, &lcrQ); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eQosLcr.Entry, lcrQ.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eQosLcr.Entry, lcrQ.Entry) - // Test *qos strategy here - cdQos := &CallDescriptor{ - TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), - TimeEnd: time.Date(2015, 04, 06, 17, 41, 0, 0, time.UTC), - Tenant: "tenant12", - Direction: utils.OUT, - Category: "call_qos", - Destination: "+4986517174963", - Account: "dan", - Subject: "dan", - } - eQosLcr := &LCRCost{ - Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS, Weight: 10.0}, - SupplierCosts: []*LCRSupplierCost{ - &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, QOS: map[string]float64{ACD: -1, PDD: -1, TCD: -1, ASR: -1, ACC: -1, TCC: -1, DDC: -1}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 300, PDD: -1, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 180, PDD: -1, TCD: 180, ASR: 100, ACC: 1, TCC: 1, DDC: 1}, qosSortParams: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}}, - }, - } - var lcrQ LCRCost - if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQos}, &lcrQ); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eQosLcr.Entry, lcrQ.Entry) { - t.Errorf("Expecting: %+v, received: %+v", eQosLcr.Entry, lcrQ.Entry) - - } else if !reflect.DeepEqual(eQosLcr.SupplierCosts, lcrQ.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eQosLcr.SupplierCosts, lcrQ.SupplierCosts) - } + } else if !reflect.DeepEqual(eQosLcr.SupplierCosts, lcrQ.SupplierCosts) { + t.Errorf("Expecting: %+v, received: %+v", eQosLcr.SupplierCosts, lcrQ.SupplierCosts) + } + */ } func TestResponderGobSMCost(t *testing.T) { diff --git a/engine/statscdrs_test.go b/engine/statscdrs_test.go deleted file mode 100644 index 5b55ccac3..000000000 --- a/engine/statscdrs_test.go +++ /dev/null @@ -1,555 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ -package engine - -import ( - "testing" - "time" - - "github.com/cgrates/cgrates/utils" -) - -func TestCDRStatsQueueInit(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACC}}) - if len(sq.metrics) != 2 { - t.Error("Expected 2 metrics got ", len(sq.metrics)) - } -} - -func TestStatsValue(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}}) - cdr := &CDR{ - SetupTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - Usage: 10 * time.Second, - Cost: 1, - } - sq.AppendCDR(cdr) - cdr.Cost = 2 - sq.AppendCDR(cdr) - cdr.Cost = 3 - sq.AppendCDR(cdr) - s := sq.GetStats() - if s[ASR] != 100 || - s[ACD] != 10 || - s[TCD] != 30 || - s[ACC] != 2 || - s[TCC] != 6 { - t.Errorf("Error getting stats: %+v", s) - } -} - -func TestStatsSimplifyCDR(t *testing.T) { - cdr := &CDR{ - ToR: "tor", - OriginID: "accid", - OriginHost: "cdrhost", - Source: "cdrsource", - RequestType: "reqtype", - Direction: "direction", - Tenant: "tenant", - Category: "category", - Account: "account", - Subject: "subject", - Destination: "12345678", - SetupTime: time.Date(2014, 7, 3, 13, 43, 0, 0, time.UTC), - Usage: 10 * time.Second, - RunID: "mri", - Cost: 10, - } - sq := &CDRStatsQueue{} - qcdr := sq.simplifyCdr(cdr) - if cdr.SetupTime != qcdr.SetupTime || - cdr.AnswerTime != qcdr.AnswerTime || - cdr.Usage != qcdr.Usage || - cdr.Cost != qcdr.Cost { - t.Errorf("Failed to simplify cdr: %+v", qcdr) - } -} - -func TestAcceptCdr(t *testing.T) { - sq := NewCDRStatsQueue(nil) - cdr := &CDR{ - ToR: "tor", - OriginID: "accid", - OriginHost: "cdrhost", - Source: "cdrsource", - RequestType: "reqtype", - Direction: "direction", - Tenant: "tenant", - Category: "category", - Account: "account", - Subject: "subject", - Destination: "0723045326", - SetupTime: time.Date(2014, 7, 3, 13, 43, 0, 0, time.UTC), - Usage: 10 * time.Second, - PDD: 7 * time.Second, - Supplier: "supplier1", - DisconnectCause: "normal", - RunID: "mri", - Cost: 10, - } - sq.conf = &CdrStats{} - if sq.conf.AcceptCdr(cdr) != true { - t.Errorf("Should have accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{TOR: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{CdrHost: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{CdrSource: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Direction: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Tenant: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Category: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Account: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Subject: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{Supplier: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{DisconnectCause: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{DestinationIds: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{DestinationIds: []string{"NAT", "RET"}} - if sq.conf.AcceptCdr(cdr) != true { - t.Errorf("Should have accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{SetupInterval: []time.Time{time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC)}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{SetupInterval: []time.Time{time.Date(2014, 7, 3, 13, 42, 0, 0, time.UTC), time.Date(2014, 7, 3, 13, 43, 0, 0, time.UTC)}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{SetupInterval: []time.Time{time.Date(2014, 7, 3, 13, 42, 0, 0, time.UTC)}} - if sq.conf.AcceptCdr(cdr) != true { - t.Errorf("Should have accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{SetupInterval: []time.Time{time.Date(2014, 7, 3, 13, 42, 0, 0, time.UTC), time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC)}} - if sq.conf.AcceptCdr(cdr) != true { - t.Errorf("Should have accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{UsageInterval: []time.Duration{11 * time.Second}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{UsageInterval: []time.Duration{1 * time.Second, 10 * time.Second}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{PddInterval: []time.Duration{8 * time.Second}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{PddInterval: []time.Duration{3 * time.Second, 7 * time.Second}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{PddInterval: []time.Duration{3 * time.Second, 8 * time.Second}} - if sq.conf.AcceptCdr(cdr) != true { - t.Errorf("Should have accepted this CDR: %+v", cdr) - } -} - -func TestCDRStatsQueueIds(t *testing.T) { - cdrStats := NewStats(dm, 0) - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Errorf getting queue ids: ", err) - } - result := len(ids) - expected := 5 - if result != expected { - t.Errorf("Errorf loading stats queues. Expected %v was %v (%v)", expected, result, ids) - } -} - -func TestStatsAppendCdr(t *testing.T) { - cdrStats := NewStats(dm, 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 TestStatsGetValues(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - cdr = &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 2 * time.Second, - Cost: 4, - } - cdrStats.AppendCDR(cdr, nil) - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != 6 || valMap["ASR"] != 100 { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsReloadQueues(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - if err := cdrStats.ReloadQueues(nil, nil); err != nil { - t.Error("Error reloading queues: ", err) - } - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Error getting queue ids: ", err) - } - result := len(ids) - expected := 5 - if result != expected { - t.Errorf("Error loading stats queues. Expected %v was %v: %v", expected, result, ids) - } - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != 10 || valMap["ASR"] != 100 { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsReloadQueuesWithDefault(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdrStats.AddQueue(&CdrStats{ - Id: utils.META_DEFAULT, - }, nil) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - - if err := cdrStats.ReloadQueues(nil, nil); err != nil { - t.Error("Error reloading queues: ", err) - } - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Error getting queue ids: ", err) - } - result := len(ids) - expected := 6 - if result != expected { - t.Errorf("Error loading stats queues. Expected %v was %v", expected, result) - } - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != 10 || valMap["ASR"] != 100 { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsReloadQueuesWithIds(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - if err := cdrStats.ReloadQueues([]string{"CDRST1"}, nil); err != nil { - t.Error("Error reloading queues: ", err) - } - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Error getting queue ids: ", err) - } - result := len(ids) - expected := 6 - if result != expected { - t.Errorf("Error loading stats queues. Expected %v was %v", expected, result) - } - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != 10 || valMap["ASR"] != 100 { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsSaveQueues(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - ids := []string{} - cdrStats.GetQueueIds(0, &ids) - if _, found := cdrStats.queueSavers["CDRST1"]; !found { - t.Error("Error creating queue savers: ", cdrStats.queueSavers) - } -} - -func TestStatsResetQueues(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - if err := cdrStats.ResetQueues(nil, nil); err != nil { - t.Error("Error reloading queues: ", err) - } - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Error getting queue ids: ", err) - } - result := len(ids) - expected := 6 - if result != expected { - t.Errorf("Error loading stats queues. Expected %v was %v", expected, result) - } - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != STATS_NA || valMap["ASR"] != STATS_NA { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsResetQueuesWithIds(t *testing.T) { - cdrStats := NewStats(dm, 0) - cdr := &CDR{ - Tenant: "cgrates.org", - Category: "call", - AnswerTime: time.Now(), - SetupTime: time.Now(), - Usage: 10 * time.Second, - Cost: 10, - } - cdrStats.AppendCDR(cdr, nil) - if err := cdrStats.ResetQueues([]string{"CDRST1"}, nil); err != nil { - t.Error("Error reloading queues: ", err) - } - ids := []string{} - if err := cdrStats.GetQueueIds(0, &ids); err != nil { - t.Error("Error getting queue ids: ", err) - } - result := len(ids) - expected := 6 - if result != expected { - t.Errorf("Error loading stats queues. Expected %v was %v", expected, result) - } - valMap := make(map[string]float64) - if err := cdrStats.GetValues("CDRST2", &valMap); err != nil { - t.Error("Error getting metric values: ", err) - } - if len(valMap) != 2 || valMap["ACD"] != 10 || valMap["ASR"] != 100 { - t.Error("Error on metric map: ", valMap) - } -} - -func TestStatsSaveRestoreQeue(t *testing.T) { - sq := &CDRStatsQueue{ - conf: &CdrStats{Id: "TTT"}, - Cdrs: []*QCdr{&QCdr{Cost: 9.0}}, - } - if err := dm.DataDB().SetCdrStatsQueue(sq); err != nil { - t.Error("Error saving metric: ", err) - } - recovered, err := dm.DataDB().GetCdrStatsQueue(sq.GetId()) - if err != nil { - t.Error("Error loading metric: ", err) - } - if len(recovered.Cdrs) != 1 || recovered.Cdrs[0].Cost != sq.Cdrs[0].Cost { - t.Errorf("Expecting %+v got: %+v", sq.Cdrs[0], recovered.Cdrs[0]) - } -} - -func TestStatsPurgeTimeOne(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}, TimeWindow: 30 * time.Minute}) - cdr := &CDR{ - SetupTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - Usage: 10 * time.Second, - Cost: 1, - } - qcdr := sq.AppendCDR(cdr) - qcdr.EventTime = qcdr.SetupTime - s := sq.GetStats() - if s[ASR] != -1 || - s[ACD] != -1 || - s[TCD] != -1 || - s[ACC] != -1 || - s[TCC] != -1 { - t.Errorf("Error getting stats: %+v", s) - } -} - -func TestStatsPurgeTime(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}, TimeWindow: 30 * time.Minute}) - cdr := &CDR{ - SetupTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - Usage: 10 * time.Second, - Cost: 1, - } - qcdr := sq.AppendCDR(cdr) - qcdr.EventTime = qcdr.SetupTime - cdr.Cost = 2 - qcdr = sq.AppendCDR(cdr) - qcdr.EventTime = qcdr.SetupTime - cdr.Cost = 3 - qcdr = sq.AppendCDR(cdr) - qcdr.EventTime = qcdr.SetupTime - s := sq.GetStats() - if s[ASR] != -1 || - s[ACD] != -1 || - s[TCD] != -1 || - s[ACC] != -1 || - s[TCC] != -1 { - t.Errorf("Error getting stats: %+v", s) - } -} - -func TestStatsPurgeTimeFirst(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}, TimeWindow: 30 * time.Minute}) - cdr := &CDR{ - SetupTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - Usage: 10 * time.Second, - Cost: 1, - } - qcdr := sq.AppendCDR(cdr) - cdr.Cost = 2 - cdr.SetupTime = time.Date(2024, 7, 14, 14, 25, 0, 0, time.UTC) - cdr.AnswerTime = time.Date(2024, 7, 14, 14, 25, 0, 0, time.UTC) - qcdr.EventTime = qcdr.SetupTime - sq.AppendCDR(cdr) - cdr.Cost = 3 - sq.AppendCDR(cdr) - s := sq.GetStats() - if s[ASR] != 100 || - s[ACD] != 10 || - s[TCD] != 20 || - s[ACC] != 2.5 || - s[TCC] != 5 { - t.Errorf("Error getting stats: %+v", s) - } -} - -func TestStatsPurgeLength(t *testing.T) { - sq := NewCDRStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}, QueueLength: 1}) - cdr := &CDR{ - SetupTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), - Usage: 10 * time.Second, - Cost: 1, - } - sq.AppendCDR(cdr) - cdr.Cost = 2 - sq.AppendCDR(cdr) - cdr.Cost = 3 - sq.AppendCDR(cdr) - s := sq.GetStats() - if s[ASR] != 100 || - s[ACD] != 10 || - s[TCD] != 10 || - s[ACC] != 3 || - s[TCC] != 3 { - t.Errorf("Error getting stats: %+v", s) - } -} diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index 9b05f5b7f..b5dc8e025 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -256,7 +256,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) { Background: false, Sparse: false, } - if err = db.C(utils.TBLCDRs).EnsureIndex(idx); err != nil { + if err = db.C(utils.CDRsTBL).EnsureIndex(idx); err != nil { return } for _, idxKey := range ms.cdrsIndexes { @@ -267,7 +267,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) { Background: false, Sparse: false, } - if err = db.C(utils.TBLCDRs).EnsureIndex(idx); err != nil { + if err = db.C(utils.CDRsTBL).EnsureIndex(idx); err != nil { return } } @@ -278,7 +278,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) { Background: false, Sparse: false, } - if err = db.C(utils.TBLSMCosts).EnsureIndex(idx); err != nil { + if err = db.C(utils.SMCostsTBL).EnsureIndex(idx); err != nil { return } idx = mgo.Index{ @@ -288,7 +288,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) { Background: false, Sparse: false, } - if err = db.C(utils.TBLSMCosts).EnsureIndex(idx); err != nil { + if err = db.C(utils.SMCostsTBL).EnsureIndex(idx); err != nil { return } idx = mgo.Index{ @@ -298,7 +298,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) { Background: false, Sparse: false, } - if err = db.C(utils.TBLSMCosts).EnsureIndex(idx); err != nil { + if err = db.C(utils.SMCostsTBL).EnsureIndex(idx); err != nil { return } } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 02a219b2a..c8bf5bf38 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -888,13 +888,13 @@ func (ms *MongoStorage) SetSMCost(smc *SMCost) error { if smc.CostDetails == nil { return nil } - session, col := ms.conn(utils.TBLSMCosts) + session, col := ms.conn(utils.SMCostsTBL) defer session.Close() return col.Insert(smc) } func (ms *MongoStorage) RemoveSMCost(smc *SMCost) error { - session, col := ms.conn(utils.TBLSMCosts) + session, col := ms.conn(utils.SMCostsTBL) defer session.Close() tx := col.Bulk() tx.Remove(bson.M{"cgrid": smc.CGRID, "runid": smc.RunID}, smc) @@ -917,7 +917,7 @@ func (ms *MongoStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix stri filter[OriginIDLow] = bson.M{"$regex": bson.RegEx{Pattern: fmt.Sprintf("^%s", originIDPrefix)}} } // Execute query - session, col := ms.conn(utils.TBLSMCosts) + session, col := ms.conn(utils.SMCostsTBL) defer session.Close() iter := col.Find(filter).Iter() var smCost SMCost @@ -938,7 +938,7 @@ func (ms *MongoStorage) SetCDR(cdr *CDR, allowUpdate bool) (err error) { if cdr.OrderID == 0 { cdr.OrderID = ms.cnter.Next() } - session, col := ms.conn(utils.TBLCDRs) + session, col := ms.conn(utils.CDRsTBL) defer session.Close() if allowUpdate { _, err = col.Upsert(bson.M{CGRIDLow: cdr.CGRID, RunIDLow: cdr.RunID}, cdr) @@ -980,7 +980,7 @@ func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { } } -// _, err := col(utils.TBLCDRs).UpdateAll(bson.M{CGRIDLow: bson.M{"$in": cgrIds}}, bson.M{"$set": bson.M{"deleted_at": time.Now()}}) +// _, err := col(utils.CDRsTBL).UpdateAll(bson.M{CGRIDLow: bson.M{"$in": cgrIds}}, bson.M{"$set": bson.M{"deleted_at": time.Now()}}) func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, int64, error) { var minPDD, maxPDD, minUsage, maxUsage *time.Duration if len(qryFltr.MinPDD) != 0 { @@ -1111,7 +1111,7 @@ func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } //file.WriteString(fmt.Sprintf("AFTER: %v\n", utils.ToIJSON(filters))) //file.Close() - session, col := ms.conn(utils.TBLCDRs) + session, col := ms.conn(utils.CDRsTBL) defer session.Close() if remove { if chgd, err := col.RemoveAll(filters); err != nil { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index dc549f812..cb90a015d 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -57,7 +57,7 @@ func (self *SQLStorage) Flush(scriptsPath string) (err error) { return err } } - if _, err := self.Db.Query(fmt.Sprintf("SELECT 1 FROM %s", utils.TBLCDRs)); err != nil { + if _, err := self.Db.Query(fmt.Sprintf("SELECT 1 FROM %s", utils.CDRsTBL)); err != nil { return err } if err := SetDBVersions(self); err != nil { @@ -668,19 +668,14 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { if smc.CostDetails == nil { return nil } - tss, err := json.Marshal(smc.CostDetails) - if err != nil { - utils.Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err)) - return err - } tx := self.db.Begin() - cd := &TBLSMCosts{ + cd := &SMCostSQL{ Cgrid: smc.CGRID, RunID: smc.RunID, OriginHost: smc.OriginHost, OriginID: smc.OriginID, CostSource: smc.CostSource, - CostDetails: string(tss), + CostDetails: smc.CostDetails.AsJSON(), Usage: smc.Usage, CreatedAt: time.Now(), } @@ -695,7 +690,7 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { func (self *SQLStorage) RemoveSMCost(smc *SMCost) error { tx := self.db.Begin() - if err := tx.Where(&TBLSMCosts{Cgrid: smc.CGRID, RunID: smc.RunID}).Delete(SMCost{}).Error; err != nil { + if err := tx.Where(&SMCostSQL{Cgrid: smc.CGRID, RunID: smc.RunID}).Delete(SMCost{}).Error; err != nil { tx.Rollback() return err } @@ -706,7 +701,7 @@ func (self *SQLStorage) RemoveSMCost(smc *SMCost) error { // GetSMCosts is used to retrieve one or multiple SMCosts based on filter func (self *SQLStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix string) ([]*SMCost, error) { var smCosts []*SMCost - filter := &TBLSMCosts{} + filter := &SMCostSQL{} if cgrid != "" { filter.Cgrid = cgrid } @@ -720,7 +715,7 @@ func (self *SQLStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix stri if originIDPrefix != "" { q = self.db.Where(filter).Where(fmt.Sprintf("origin_id LIKE '%s%%'", originIDPrefix)) } - results := make([]*TBLSMCosts, 0) + results := make([]*SMCostSQL, 0) if err := q.Find(&results).Error; err != nil { return nil, err } @@ -756,73 +751,18 @@ func (self *SQLStorage) LogActionTiming(source string, at *ActionTiming, as Acti } func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { - extraFields, err := json.Marshal(cdr.ExtraFields) - if err != nil { - return err - } tx := self.db.Begin() - saved := tx.Save(&TBLCDRs{ - Cgrid: cdr.CGRID, - RunID: cdr.RunID, - OriginHost: cdr.OriginHost, - Source: cdr.Source, - OriginID: cdr.OriginID, - Tor: cdr.ToR, - RequestType: cdr.RequestType, - Direction: cdr.Direction, - Tenant: cdr.Tenant, - Category: cdr.Category, - Account: cdr.Account, - Subject: cdr.Subject, - Destination: cdr.Destination, - SetupTime: cdr.SetupTime, - Pdd: cdr.PDD.Seconds(), - AnswerTime: cdr.AnswerTime, - Usage: cdr.Usage.Seconds(), - Supplier: cdr.Supplier, - DisconnectCause: cdr.DisconnectCause, - ExtraFields: string(extraFields), - CostSource: cdr.CostSource, - Cost: cdr.Cost, - CostDetails: cdr.CostDetailsJson(), - AccountSummary: utils.ToJSON(cdr.AccountSummary), - ExtraInfo: cdr.ExtraInfo, - CreatedAt: time.Now(), - }) + cdrSql := cdr.AsCDRsql() + cdrSql.CreatedAt = time.Now() + saved := tx.Save(cdrSql) if saved.Error != nil { tx.Rollback() if !allowUpdate { return saved.Error } tx = self.db.Begin() - updated := tx.Model(&TBLCDRs{}).Where(&TBLCDRs{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates( - TBLCDRs{ - OriginHost: cdr.OriginHost, - Source: cdr.Source, - OriginID: cdr.OriginID, - Tor: cdr.ToR, - RequestType: cdr.RequestType, - Direction: cdr.Direction, - Tenant: cdr.Tenant, - Category: cdr.Category, - Account: cdr.Account, - Subject: cdr.Subject, - Destination: cdr.Destination, - SetupTime: cdr.SetupTime, - Pdd: cdr.PDD.Seconds(), - AnswerTime: cdr.AnswerTime, - Usage: cdr.Usage.Seconds(), - Supplier: cdr.Supplier, - DisconnectCause: cdr.DisconnectCause, - ExtraFields: string(extraFields), - CostSource: cdr.CostSource, - Cost: cdr.Cost, - CostDetails: cdr.CostDetailsJson(), - AccountSummary: utils.ToJSON(cdr.AccountSummary), - ExtraInfo: cdr.ExtraInfo, - UpdatedAt: time.Now(), - }, - ) + cdrSql.UpdatedAt = time.Now() + updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) if updated.Error != nil { tx.Rollback() return updated.Error @@ -836,7 +776,7 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { // qryFltr.Unscoped will ignore soft deletes or delete records permanently func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, int64, error) { var cdrs []*CDR - q := self.db.Table(utils.TBLCDRs).Select("*") + q := self.db.Table(utils.CDRsTBL).Select("*") if qryFltr.Unscoped { q = q.Unscoped() } @@ -942,10 +882,10 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, q = q.Where("disconnect_cause not in (?)", qryFltr.NotDisconnectCauses) } if len(qryFltr.Costs) != 0 { - q = q.Where(utils.TBLCDRs+".cost in (?)", qryFltr.Costs) + q = q.Where(utils.CDRsTBL+".cost in (?)", qryFltr.Costs) } if len(qryFltr.NotCosts) != 0 { - q = q.Where(utils.TBLCDRs+".cost not in (?)", qryFltr.NotCosts) + q = q.Where(utils.CDRsTBL+".cost not in (?)", qryFltr.NotCosts) } if len(qryFltr.ExtraFields) != 0 { // Extra fields searches, implemented as contains in extra field qIds := bytes.NewBufferString("(") @@ -982,10 +922,10 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, q = q.Where(qIds.String()) } if qryFltr.OrderIDStart != nil { // Keep backwards compatible by testing 0 value - q = q.Where(utils.TBLCDRs+".id >= ?", *qryFltr.OrderIDStart) + q = q.Where(utils.CDRsTBL+".id >= ?", *qryFltr.OrderIDStart) } if qryFltr.OrderIDEnd != nil { - q = q.Where(utils.TBLCDRs+".id < ?", *qryFltr.OrderIDEnd) + q = q.Where(utils.CDRsTBL+".id < ?", *qryFltr.OrderIDEnd) } if qryFltr.SetupTimeStart != nil { q = q.Where("setup_time >= ?", qryFltr.SetupTimeStart) @@ -1012,41 +952,41 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, q = q.Where("updated_at < ?", qryFltr.UpdatedAtEnd) } if len(qryFltr.MinUsage) != 0 { - if minUsage, err := utils.ParseDurationWithSecs(qryFltr.MinUsage); err != nil { + minUsage, err := utils.ParseDurationWithNanosecs(qryFltr.MinUsage) + if err != nil { return nil, 0, err + } + if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage + q = q.Where("`usage` >= ?", minUsage.Nanoseconds()) } else { - if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage - q = q.Where("`usage` >= ?", minUsage.Seconds()) - } else { - q = q.Where("usage >= ?", minUsage.Seconds()) - } + q = q.Where("usage >= ?", minUsage.Nanoseconds()) } } if len(qryFltr.MaxUsage) != 0 { - if maxUsage, err := utils.ParseDurationWithSecs(qryFltr.MaxUsage); err != nil { + maxUsage, err := utils.ParseDurationWithNanosecs(qryFltr.MaxUsage) + if err != nil { return nil, 0, err + } + if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage + q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) } else { - if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage - q = q.Where("`usage` < ?", maxUsage.Seconds()) - } else { - q = q.Where("usage < ?", maxUsage.Seconds()) - } + q = q.Where("usage < ?", maxUsage.Nanoseconds()) } } if len(qryFltr.MinPDD) != 0 { - if minPDD, err := utils.ParseDurationWithSecs(qryFltr.MinPDD); err != nil { + if minPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { return nil, 0, err } else { - q = q.Where("pdd >= ?", minPDD.Seconds()) + q = q.Where("pdd >= ?", minPDD.Nanoseconds()) } } if len(qryFltr.MaxPDD) != 0 { - if maxPDD, err := utils.ParseDurationWithSecs(qryFltr.MaxPDD); err != nil { + if maxPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { return nil, 0, err } else { - q = q.Where("pdd < ?", maxPDD.Seconds()) + q = q.Where("pdd < ?", maxPDD.Nanoseconds()) } } @@ -1087,58 +1027,16 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, return nil, cnt, nil } // Execute query - results := make([]*TBLCDRs, 0) + results := make([]*CDRsql, 0) if err := q.Find(&results).Error; err != nil { return nil, 0, err } for _, result := range results { - extraFieldsMp := make(map[string]string) - if result.ExtraFields != "" { - if err := json.Unmarshal([]byte(result.ExtraFields), &extraFieldsMp); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %v, error: %s", result.Cgrid, result.RunID, err.Error()) - } + if cdr, err := NewCDRFromSQL(result); err != nil { + return nil, 0, err + } else { + cdrs = append(cdrs, cdr) } - var callCost CallCost - if result.CostDetails != "" { - if err := json.Unmarshal([]byte(result.CostDetails), &callCost); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal callcost error for cgrid: %s, runid: %v, error: %s", result.Cgrid, result.RunID, err.Error()) - } - } - acntSummary, err := NewAccountSummaryFromJSON(result.AccountSummary) - if err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal account summary error for cgrid: %s, runid: %v, error: %s", result.Cgrid, result.RunID, err.Error()) - } - usageDur := time.Duration(result.Usage * utils.NANO_MULTIPLIER) - pddDur := time.Duration(result.Pdd * utils.NANO_MULTIPLIER) - storCdr := &CDR{ - CGRID: result.Cgrid, - RunID: result.RunID, - OrderID: result.ID, - OriginHost: result.OriginHost, - Source: result.Source, - OriginID: result.OriginID, - ToR: result.Tor, - RequestType: result.RequestType, - Direction: result.Direction, - Tenant: result.Tenant, - Category: result.Category, - Account: result.Account, - Subject: result.Subject, - Destination: result.Destination, - SetupTime: result.SetupTime, - PDD: pddDur, - AnswerTime: result.AnswerTime, - Usage: usageDur, - Supplier: result.Supplier, - DisconnectCause: result.DisconnectCause, - ExtraFields: extraFieldsMp, - CostSource: result.CostSource, - Cost: result.Cost, - CostDetails: &callCost, - AccountSummary: acntSummary, - ExtraInfo: result.ExtraInfo, - } - cdrs = append(cdrs, storCdr) } if len(cdrs) == 0 && !remove { return cdrs, 0, utils.ErrNotFound diff --git a/engine/suretax_test.go b/engine/suretax_test.go index 63c1cb404..16d554ed5 100644 --- a/engine/suretax_test.go +++ b/engine/suretax_test.go @@ -30,11 +30,16 @@ import ( func TestNewSureTaxRequest(t *testing.T) { CGRID := utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()) cdr := &CDR{CGRID: CGRID, OrderID: 123, ToR: utils.VOICE, - OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(12) * time.Second, PDD: time.Duration(7) * time.Second, - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, + OriginID: "dsafdsaf", OriginHost: "192.168.1.1", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(12) * time.Second, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Cost: 1.01, Rated: true, } cfg, _ := config.NewDefaultCGRConfig() stCfg := cfg.SureTaxCfg() diff --git a/engine/users_test.go b/engine/users_test.go index 6983bb7a0..ca51f5261 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -610,7 +610,6 @@ func TestUsersUsageRecordGetLoadUserProfile(t *testing.T) { ur := &UsageRecord{ ToR: utils.USERS, RequestType: utils.USERS, - Direction: "*out", Tenant: "", Category: "call", Account: utils.USERS, @@ -628,7 +627,6 @@ func TestUsersUsageRecordGetLoadUserProfile(t *testing.T) { expected := &UsageRecord{ ToR: "04", RequestType: "4", - Direction: "*out", Tenant: "", Category: "call", Account: "rif", @@ -657,7 +655,6 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFields(t *testing.T) { ur := &ExternalCDR{ ToR: utils.USERS, RequestType: utils.USERS, - Direction: "*out", Tenant: "", Category: "call", Account: utils.USERS, @@ -678,7 +675,6 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFields(t *testing.T) { expected := &ExternalCDR{ ToR: "04", RequestType: "4", - Direction: "*out", Tenant: "", Category: "call", Account: "rif", @@ -710,7 +706,6 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { ur := &ExternalCDR{ ToR: utils.USERS, RequestType: utils.USERS, - Direction: "*out", Tenant: "", Category: "call", Account: utils.USERS, @@ -744,7 +739,6 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFieldsSet(t *testing.T) { ur := &ExternalCDR{ ToR: utils.USERS, RequestType: utils.USERS, - Direction: "*out", Tenant: "", Category: "call", Account: utils.USERS, @@ -766,7 +760,6 @@ func TestUsersExternalCDRGetLoadUserProfileExtraFieldsSet(t *testing.T) { expected := &ExternalCDR{ ToR: "04", RequestType: "4", - Direction: "*out", Tenant: "", Category: "call", Account: "rif", diff --git a/engine/version.go b/engine/version.go index 18df01307..9abfde5c8 100644 --- a/engine/version.go +++ b/engine/version.go @@ -104,9 +104,17 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } +func CurrentStorDBVersions() Versions { + return Versions{utils.COST_DETAILS: 2, utils.CDRsTBL: 2} +} + +func CurrentDataDBVersions() Versions { + return Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} +} + func CurrentDBVersions(storType string) Versions { - dataDbVersions := Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} - storDbVersions := Versions{utils.COST_DETAILS: 2} + dataDbVersions := CurrentDataDBVersions() + storDbVersions := CurrentStorDBVersions() allVersions := make(Versions) for k, v := range dataDbVersions { @@ -127,13 +135,5 @@ func CurrentDBVersions(storType string) Versions { return nil } -func CurrentStorDBVersions() Versions { - return Versions{utils.COST_DETAILS: 2} -} - -func CurrentDataDBVersions() Versions { - return Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} -} - // Versions will keep trac of various item versions type Versions map[string]int64 // map[item]versionNr diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index 763f0dd20..18a3a59dd 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -94,7 +94,7 @@ RP_ANY,DR_ANY_1CNT,*any,10` } func TestAuthPostpaidNoAcnt(t *testing.T) { - cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Tenant: "cgrates.org", Category: "call", Account: "nonexistent", Subject: "testauthpostpaid1", Destination: "4986517174963", SetupTime: time.Date(2015, 8, 27, 11, 26, 0, 0, time.UTC)} var maxSessionTime float64 @@ -105,7 +105,7 @@ func TestAuthPostpaidNoAcnt(t *testing.T) { func TestAuthPostpaidNoDestination(t *testing.T) { // Test subject which does not have destination attached - cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Tenant: "cgrates.org", Category: "call", Account: "testauthpostpaid1", Subject: "testauthpostpaid1", Destination: "441231234", SetupTime: time.Date(2015, 8, 27, 11, 26, 0, 0, time.UTC)} var maxSessionTime float64 @@ -116,7 +116,7 @@ func TestAuthPostpaidNoDestination(t *testing.T) { func TestAuthPostpaidFallbackDest(t *testing.T) { // Test subject which has fallback for destination - cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Tenant: "cgrates.org", Category: "call", Account: "testauthpostpaid1", Subject: "testauthpostpaid2", Destination: "441231234", SetupTime: time.Date(2015, 8, 27, 11, 26, 0, 0, time.UTC)} var maxSessionTime float64 @@ -129,7 +129,7 @@ func TestAuthPostpaidFallbackDest(t *testing.T) { func TestAuthPostpaidWithDestination(t *testing.T) { // Test subject which does not have destination attached - cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Tenant: "cgrates.org", Category: "call", Account: "testauthpostpaid1", Subject: "testauthpostpaid1", Destination: "4986517174963", SetupTime: time.Date(2015, 8, 27, 11, 26, 0, 0, time.UTC)} var maxSessionTime float64 diff --git a/general_tests/fsevcorelate_test.go b/general_tests/fsevcorelate_test.go index 448c88703..d7e06ac36 100644 --- a/general_tests/fsevcorelate_test.go +++ b/general_tests/fsevcorelate_test.go @@ -569,9 +569,6 @@ func TestEvCdrCorelate(t *testing.T) { if evStoredCdr.RequestType != jsnStoredCdr.RequestType { t.Errorf("evStoredCdr.RequestType: %s, jsnStoredCdr.RequestType: %s", evStoredCdr.RequestType, jsnStoredCdr.RequestType) } - if evStoredCdr.Direction != jsnStoredCdr.Direction { - t.Errorf("evStoredCdr.Direction: %s, jsnStoredCdr.Direction: %s", evStoredCdr.Direction, jsnStoredCdr.Direction) - } if evStoredCdr.Tenant != jsnStoredCdr.Tenant { t.Errorf("evStoredCdr.Tenant: %s, jsnStoredCdr.Tenant: %s", evStoredCdr.Tenant, jsnStoredCdr.Tenant) } @@ -590,19 +587,10 @@ func TestEvCdrCorelate(t *testing.T) { if evStoredCdr.SetupTime != jsnStoredCdr.SetupTime { t.Errorf("evStoredCdr.SetupTime: %v, jsnStoredCdr.SetupTime: %v", evStoredCdr.SetupTime, jsnStoredCdr.SetupTime) } - if evStoredCdr.PDD != jsnStoredCdr.PDD { - t.Errorf("evStoredCdr.PDD: %v, jsnStoredCdr.PDD: %v", evStoredCdr.PDD, jsnStoredCdr.PDD) - } if evStoredCdr.AnswerTime != jsnStoredCdr.AnswerTime { t.Errorf("evStoredCdr.AnswerTime: %v, jsnStoredCdr.AnswerTime: %v", evStoredCdr.AnswerTime, jsnStoredCdr.AnswerTime) } if evStoredCdr.Usage != jsnStoredCdr.Usage { t.Errorf("evStoredCdr.Usage: %v, jsnStoredCdr.Usage: %v", evStoredCdr.Usage, jsnStoredCdr.Usage) } - if evStoredCdr.Supplier != jsnStoredCdr.Supplier { - t.Errorf("evStoredCdr.Supplier: %s, jsnStoredCdr.Supplier: %s", evStoredCdr.Supplier, jsnStoredCdr.Supplier) - } - if evStoredCdr.DisconnectCause != jsnStoredCdr.DisconnectCause { - t.Errorf("evStoredCdr.DisconnectCause: %s, jsnStoredCdr.DisconnectCause: %s", evStoredCdr.DisconnectCause, jsnStoredCdr.DisconnectCause) - } } diff --git a/sessionmanager/fsevent.go b/sessionmanager/fsevent.go index 790b76d18..5a546060f 100644 --- a/sessionmanager/fsevent.go +++ b/sessionmanager/fsevent.go @@ -347,7 +347,6 @@ func (fsev FSEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.OriginHost = fsev.GetOriginatorIP(utils.META_DEFAULT) storCdr.Source = "FS_" + fsev.GetName() storCdr.RequestType = fsev.GetReqType(utils.META_DEFAULT) - storCdr.Direction = fsev.GetDirection(utils.META_DEFAULT) storCdr.Tenant = fsev.GetTenant(utils.META_DEFAULT) storCdr.Category = fsev.GetCategory(utils.META_DEFAULT) storCdr.Account = fsev.GetAccount(utils.META_DEFAULT) @@ -356,11 +355,8 @@ func (fsev FSEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.SetupTime, _ = fsev.GetSetupTime(utils.META_DEFAULT, timezone) storCdr.AnswerTime, _ = fsev.GetAnswerTime(utils.META_DEFAULT, timezone) storCdr.Usage, _ = fsev.GetDuration(utils.META_DEFAULT) - storCdr.PDD, _ = fsev.GetPdd(utils.META_DEFAULT) storCdr.ExtraFields = fsev.GetExtraFields() storCdr.Cost = -1 - storCdr.Supplier = fsev.GetSupplier(utils.META_DEFAULT) - storCdr.DisconnectCause = fsev.GetDisconnectCause(utils.META_DEFAULT) return storCdr } diff --git a/sessionmanager/fsevent_test.go b/sessionmanager/fsevent_test.go index 8bdd1a6be..3c68a7f41 100644 --- a/sessionmanager/fsevent_test.go +++ b/sessionmanager/fsevent_test.go @@ -371,7 +371,6 @@ func TestEventParseStatic(t *testing.T) { answerTime, _ := ev.GetAnswerTime("^2013-12-07 08:42:24", "") dur, _ := ev.GetDuration("^60s") if ev.GetReqType("^test") != "test" || - ev.GetDirection("^test") != "test" || ev.GetTenant("^test") != "test" || ev.GetCategory("^test") != "test" || ev.GetAccount("^test") != "test" || @@ -379,12 +378,9 @@ func TestEventParseStatic(t *testing.T) { ev.GetDestination("^test") != "test" || setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) || answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) || - dur != time.Duration(60)*time.Second || - ev.GetSupplier("^test") != "test" || - ev.GetDisconnectCause("^test") != "test" { + dur != time.Duration(60)*time.Second { t.Error("Values out of static not matching", ev.GetReqType("^test") != "test", - ev.GetDirection("^test") != "test", ev.GetTenant("^test") != "test", ev.GetCategory("^test") != "test", ev.GetAccount("^test") != "test", @@ -392,9 +388,7 @@ func TestEventParseStatic(t *testing.T) { ev.GetDestination("^test") != "test", setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), - dur != time.Duration(60)*time.Second, - ev.GetSupplier("^test") != "test", - ev.GetDisconnectCause("^test") != "test") + dur != time.Duration(60)*time.Second) } } @@ -424,7 +418,6 @@ Task-Runtime: 1349437318` answerTime, _ := ev.GetAnswerTime("Event-Date-Local", "") dur, _ := ev.GetDuration("Event-Calling-Line-Number") if ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net" || - ev.GetDirection("FreeSWITCH-Hostname") != "*out" || ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net" || ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net" || ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net" || @@ -432,12 +425,9 @@ Task-Runtime: 1349437318` ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net" || setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) || answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) || - dur != time.Duration(65)*time.Second || - ev.GetSupplier("FreeSWITCH-Hostname") != "h1.ip-switch.net" || - ev.GetDisconnectCause("FreeSWITCH-Hostname") != "h1.ip-switch.net" { + dur != time.Duration(65)*time.Second { t.Error("Values out of static not matching", ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net", - ev.GetDirection("FreeSWITCH-Hostname") != "*out", ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net", ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net", ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net", @@ -445,9 +435,7 @@ Task-Runtime: 1349437318` ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net", setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC), answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC), - dur != time.Duration(65)*time.Second, - ev.GetSupplier("FreeSWITCH-Hostname") != "h1.ip-switch.net", - ev.GetDisconnectCause("FreeSWITCH-Hostname") != "h1.ip-switch.net") + dur != time.Duration(65)*time.Second) } } @@ -482,7 +470,6 @@ func TestParseFsHangup(t *testing.T) { answerTime, _ := ev.GetAnswerTime(utils.META_DEFAULT, "") dur, _ := ev.GetDuration(utils.META_DEFAULT) if ev.GetReqType(utils.META_DEFAULT) != utils.META_PREPAID || - ev.GetDirection(utils.META_DEFAULT) != "*out" || ev.GetTenant(utils.META_DEFAULT) != "cgrates.org" || ev.GetCategory(utils.META_DEFAULT) != "call" || ev.GetAccount(utils.META_DEFAULT) != "1001" || @@ -490,12 +477,9 @@ func TestParseFsHangup(t *testing.T) { ev.GetDestination(utils.META_DEFAULT) != "1003" || setupTime.UTC() != time.Date(2015, 7, 7, 14, 52, 8, 0, time.UTC) || answerTime.UTC() != time.Date(2015, 7, 7, 14, 52, 8, 0, time.UTC) || - dur != time.Duration(66)*time.Second || - ev.GetSupplier(utils.META_DEFAULT) != "supplier1" || - ev.GetDisconnectCause(utils.META_DEFAULT) != "NORMAL_CLEARING" { + dur != time.Duration(66)*time.Second { t.Error("Default values not matching", ev.GetReqType(utils.META_DEFAULT) != utils.META_PREPAID, - ev.GetDirection(utils.META_DEFAULT) != "*out", ev.GetTenant(utils.META_DEFAULT) != "cgrates.org", ev.GetCategory(utils.META_DEFAULT) != "call", ev.GetAccount(utils.META_DEFAULT) != "1001", @@ -503,9 +487,7 @@ func TestParseFsHangup(t *testing.T) { ev.GetDestination(utils.META_DEFAULT) != "1003", setupTime.UTC() != time.Date(2015, 7, 7, 14, 52, 8, 0, time.UTC), answerTime.UTC() != time.Date(2015, 7, 7, 14, 52, 8, 0, time.UTC), - dur != time.Duration(66)*time.Second, - ev.GetSupplier(utils.META_DEFAULT) != "supplier1", - ev.GetDisconnectCause(utils.META_DEFAULT) != "NORMAL_CLEARING") + dur != time.Duration(66)*time.Second) } } @@ -635,11 +617,12 @@ func TestFsEvAsStoredCdr(t *testing.T) { setupTime, _ := utils.ParseTimeDetectLayout("1436280728", "") aTime, _ := utils.ParseTimeDetectLayout("1436280728", "") eStoredCdr := &engine.CDR{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", - ToR: utils.VOICE, OriginID: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", OriginHost: "10.0.3.15", Source: "FS_CHANNEL_HANGUP_COMPLETE", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", + ToR: utils.VOICE, OriginID: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", + OriginHost: "10.0.3.15", Source: "FS_CHANNEL_HANGUP_COMPLETE", RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: setupTime, AnswerTime: aTime, - Usage: time.Duration(66) * time.Second, PDD: time.Duration(28) * time.Millisecond, Supplier: "supplier1", - DisconnectCause: "NORMAL_CLEARING", ExtraFields: make(map[string]string), Cost: -1} + Usage: time.Duration(66) * time.Second, + ExtraFields: make(map[string]string), Cost: -1} if storedCdr := ev.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index f68ef9eb9..c378672ee 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -128,7 +128,7 @@ func (sm *FSSessionManager) setCgrLcr(ev engine.Event, connId string) error { } cd := &engine.CallDescriptor{ CgrID: ev.GetCgrId(sm.Timezone()), - Direction: ev.GetDirection(utils.META_DEFAULT), + Direction: utils.OUT, Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT), diff --git a/sessionmanager/kamevent.go b/sessionmanager/kamevent.go index 6556ae507..e2077eddc 100644 --- a/sessionmanager/kamevent.go +++ b/sessionmanager/kamevent.go @@ -328,7 +328,6 @@ func (kev KamEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.OriginHost = kev.GetOriginatorIP(utils.META_DEFAULT) storCdr.Source = kev.GetCdrSource() storCdr.RequestType = kev.GetReqType(utils.META_DEFAULT) - storCdr.Direction = kev.GetDirection(utils.META_DEFAULT) storCdr.Tenant = kev.GetTenant(utils.META_DEFAULT) storCdr.Category = kev.GetCategory(utils.META_DEFAULT) storCdr.Account = kev.GetAccount(utils.META_DEFAULT) @@ -337,9 +336,6 @@ func (kev KamEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.SetupTime, _ = kev.GetSetupTime(utils.META_DEFAULT, timezone) storCdr.AnswerTime, _ = kev.GetAnswerTime(utils.META_DEFAULT, timezone) storCdr.Usage, _ = kev.GetDuration(utils.META_DEFAULT) - storCdr.PDD, _ = kev.GetPdd(utils.META_DEFAULT) - storCdr.Supplier = kev.GetSupplier(utils.META_DEFAULT) - storCdr.DisconnectCause = kev.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = kev.GetExtraFields() storCdr.Cost = -1 diff --git a/sessionmanager/osipsevent.go b/sessionmanager/osipsevent.go index 4057d2eea..2fb3f3ce3 100644 --- a/sessionmanager/osipsevent.go +++ b/sessionmanager/osipsevent.go @@ -272,7 +272,6 @@ func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.OriginHost = osipsEv.GetOriginatorIP(utils.META_DEFAULT) storCdr.Source = "OSIPS_" + osipsEv.GetName() storCdr.RequestType = osipsEv.GetReqType(utils.META_DEFAULT) - storCdr.Direction = osipsEv.GetDirection(utils.META_DEFAULT) storCdr.Tenant = osipsEv.GetTenant(utils.META_DEFAULT) storCdr.Category = osipsEv.GetCategory(utils.META_DEFAULT) storCdr.Account = osipsEv.GetAccount(utils.META_DEFAULT) @@ -281,9 +280,6 @@ func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.CDR { storCdr.SetupTime, _ = osipsEv.GetSetupTime(utils.META_DEFAULT, timezone) storCdr.AnswerTime, _ = osipsEv.GetAnswerTime(utils.META_DEFAULT, timezone) storCdr.Usage, _ = osipsEv.GetDuration(utils.META_DEFAULT) - storCdr.PDD, _ = osipsEv.GetPdd(utils.META_DEFAULT) - storCdr.Supplier = osipsEv.GetSupplier(utils.META_DEFAULT) - storCdr.DisconnectCause = osipsEv.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = osipsEv.GetExtraFields() storCdr.Cost = -1 return storCdr diff --git a/sessionmanager/osipsevent_test.go b/sessionmanager/osipsevent_test.go index 31b0e4e8f..102b2dab7 100644 --- a/sessionmanager/osipsevent_test.go +++ b/sessionmanager/osipsevent_test.go @@ -142,12 +142,15 @@ func TestOsipsEventMissingParameter(t *testing.T) { func TestOsipsEventAsStoredCdr(t *testing.T) { setupTime, _ := utils.ParseTimeDetectLayout("1406370492", "") answerTime, _ := utils.ParseTimeDetectLayout("1406370499", "") - eStoredCdr := &engine.CDR{CGRID: utils.Sha1("ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", setupTime.UTC().String()), - ToR: utils.VOICE, OriginID: "ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", OriginHost: "172.16.254.77", Source: "OSIPS_E_ACC_CDR", + eStoredCdr := &engine.CDR{ + CGRID: utils.Sha1("ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", setupTime.UTC().String()), + ToR: utils.VOICE, OriginID: "ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", + OriginHost: "172.16.254.77", Source: "OSIPS_E_ACC_CDR", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "itsyscom.com", Category: "call", Account: "dan", Subject: "dan", + Tenant: "itsyscom.com", Category: "call", Account: "dan", Subject: "dan", Destination: "+4986517174963", SetupTime: setupTime, AnswerTime: answerTime, - Usage: time.Duration(20) * time.Second, PDD: time.Duration(3) * time.Second, Supplier: "supplier3", DisconnectCause: "200", ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} + Usage: time.Duration(20) * time.Second, + ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} if storedCdr := osipsEv.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } @@ -163,8 +166,8 @@ func TestOsipsAccMissedToStoredCdr(t *testing.T) { }} eStoredCdr := &engine.CDR{CGRID: utils.Sha1("27b1e6679ad0109b5d756e42bb4c9c28@0:0:0:0:0:0:0:0", setupTime.UTC().String()), ToR: utils.VOICE, OriginID: "27b1e6679ad0109b5d756e42bb4c9c28@0:0:0:0:0:0:0:0", OriginHost: "172.16.254.77", Source: "OSIPS_E_ACC_MISSED_EVENT", - RequestType: utils.META_PSEUDOPREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Supplier: "supplier1", - DisconnectCause: "404", Destination: "1002", SetupTime: setupTime, AnswerTime: setupTime, + RequestType: utils.META_PSEUDOPREPAID, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", + Destination: "1002", SetupTime: setupTime, AnswerTime: setupTime, Usage: time.Duration(0), ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} if storedCdr := osipsEv.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 4e528a546..f91f2923a 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -272,7 +272,6 @@ func (s *Session) AsActiveSessions() []*ActiveSession { sTime, _ := s.eventStart.GetSetupTime(utils.META_DEFAULT, s.sessionManager.Timezone()) aTime, _ := s.eventStart.GetAnswerTime(utils.META_DEFAULT, s.sessionManager.Timezone()) usage, _ := s.eventStart.GetDuration(utils.META_DEFAULT) - pdd, _ := s.eventStart.GetPdd(utils.META_DEFAULT) for _, sessionRun := range s.sessionRuns { aSession := &ActiveSession{ CGRID: s.eventStart.GetCgrId(s.sessionManager.Timezone()), @@ -281,7 +280,6 @@ func (s *Session) AsActiveSessions() []*ActiveSession { CdrHost: s.eventStart.GetOriginatorIP(utils.META_DEFAULT), CdrSource: "FS_" + s.eventStart.GetName(), ReqType: s.eventStart.GetReqType(utils.META_DEFAULT), - Direction: s.eventStart.GetDirection(utils.META_DEFAULT), Tenant: s.eventStart.GetTenant(utils.META_DEFAULT), Category: s.eventStart.GetCategory(utils.META_DEFAULT), Account: s.eventStart.GetAccount(utils.META_DEFAULT), @@ -290,9 +288,7 @@ func (s *Session) AsActiveSessions() []*ActiveSession { SetupTime: sTime, AnswerTime: aTime, Usage: usage, - Pdd: pdd, ExtraFields: s.eventStart.GetExtraFields(), - Supplier: s.eventStart.GetSupplier(utils.META_DEFAULT), SMId: "UNKNOWN", } if sessionRun.DerivedCharger != nil { @@ -326,18 +322,15 @@ type ActiveSession struct { OriginID string // represents the unique accounting id given by the telecom switch generating the CDR CdrHost string // represents the IP address of the host generating the CDR (automatically populated by the server) CdrSource string // formally identifies the source of the CDR (free form field) - ReqType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server . - Direction string // matching the supported direction identifiers of the CGRateS <*out> + ReqType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server Tenant string // tenant whom this record belongs Category string // free-form filter for this record, matching the category defined in rating profiles. Account string // account id (accounting subsystem) the record should be attached to Subject string // rating subject (rating subsystem) this record should be attached to Destination string // destination to be charged SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. - Pdd time.Duration // PDD value AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp. Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call) - Supplier string // Supplier information when available ExtraFields map[string]string // Extra fields to be stored in CDR SMId string SMConnId string diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 0f6091ebe..c2e7dffc5 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -424,7 +424,6 @@ func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) * storCdr.OriginHost = self.GetOriginatorIP(utils.META_DEFAULT) storCdr.Source = self.GetCdrSource() storCdr.RequestType = utils.FirstNonEmpty(self.GetReqType(utils.META_DEFAULT), storCdr.RequestType) - storCdr.Direction = utils.FirstNonEmpty(self.GetDirection(utils.META_DEFAULT), storCdr.Direction) storCdr.Tenant = utils.FirstNonEmpty(self.GetTenant(utils.META_DEFAULT), storCdr.Tenant) storCdr.Category = utils.FirstNonEmpty(self.GetCategory(utils.META_DEFAULT), storCdr.Category) storCdr.Account = self.GetAccount(utils.META_DEFAULT) @@ -433,9 +432,6 @@ func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) * storCdr.SetupTime, _ = self.GetSetupTime(utils.META_DEFAULT, timezone) storCdr.AnswerTime, _ = self.GetAnswerTime(utils.META_DEFAULT, timezone) storCdr.Usage, _ = self.GetUsage(utils.META_DEFAULT) - storCdr.PDD, _ = self.GetPdd(utils.META_DEFAULT) - storCdr.Supplier = self.GetSupplier(utils.META_DEFAULT) - storCdr.DisconnectCause = self.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = self.GetExtraFields() storCdr.Cost = -1 return storCdr diff --git a/sessionmanager/smg_event_test.go b/sessionmanager/smg_event_test.go index 103c2eac3..e95bdfbe1 100644 --- a/sessionmanager/smg_event_test.go +++ b/sessionmanager/smg_event_test.go @@ -172,10 +172,12 @@ func TestSMGenericEventAsStoredCdr(t *testing.T) { smGev["Extra1"] = "Value1" smGev["Extra2"] = 5 eStoredCdr := &engine.CDR{CGRID: "70c4d16dce41d1f2777b4e8442cff39cf87f5f19", - ToR: utils.SMS, OriginID: "12345", OriginHost: "10.0.3.15", Source: "SMG_TEST_EVENT", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "account1", Subject: "subject1", - Destination: "+4986517174963", SetupTime: time.Date(2015, 11, 9, 14, 21, 24, 0, time.UTC), AnswerTime: time.Date(2015, 11, 9, 14, 22, 2, 0, time.UTC), - Usage: time.Duration(83) * time.Second, PDD: time.Duration(300) * time.Millisecond, Supplier: "supplier1", DisconnectCause: "NORMAL_DISCONNECT", + ToR: utils.SMS, OriginID: "12345", OriginHost: "10.0.3.15", Source: "SMG_TEST_EVENT", + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", Category: "call", Account: "account1", Subject: "subject1", + Destination: "+4986517174963", SetupTime: time.Date(2015, 11, 9, 14, 21, 24, 0, time.UTC), + AnswerTime: time.Date(2015, 11, 9, 14, 22, 2, 0, time.UTC), + Usage: time.Duration(83) * time.Second, ExtraFields: map[string]string{"Extra1": "Value1", "Extra2": "5"}, Cost: -1} if storedCdr := smGev.AsStoredCdr(cfg, "UTC"); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index fe5e0f49c..fae1689d0 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -261,7 +261,6 @@ func (self *SMGSession) AsActiveSession(timezone string) *ActiveSession { defer self.mux.RUnlock() sTime, _ := self.EventStart.GetSetupTime(utils.META_DEFAULT, timezone) aTime, _ := self.EventStart.GetAnswerTime(utils.META_DEFAULT, timezone) - pdd, _ := self.EventStart.GetPdd(utils.META_DEFAULT) aSession := &ActiveSession{ CGRID: self.CGRID, TOR: self.EventStart.GetTOR(utils.META_DEFAULT), @@ -270,7 +269,6 @@ func (self *SMGSession) AsActiveSession(timezone string) *ActiveSession { CdrHost: self.EventStart.GetOriginatorIP(utils.META_DEFAULT), CdrSource: self.EventStart.GetCdrSource(), ReqType: self.EventStart.GetReqType(utils.META_DEFAULT), - Direction: self.EventStart.GetDirection(utils.META_DEFAULT), Tenant: self.EventStart.GetTenant(utils.META_DEFAULT), Category: self.EventStart.GetCategory(utils.META_DEFAULT), Account: self.EventStart.GetAccount(utils.META_DEFAULT), @@ -279,9 +277,7 @@ func (self *SMGSession) AsActiveSession(timezone string) *ActiveSession { SetupTime: sTime, AnswerTime: aTime, Usage: self.TotalUsage, - Pdd: pdd, ExtraFields: self.EventStart.GetExtraFields(), - Supplier: self.EventStart.GetSupplier(utils.META_DEFAULT), SMId: "CGR-DA", } if self.CD != nil { diff --git a/utils/consts.go b/utils/consts.go index aa0c6871c..8dec0b96e 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -112,8 +112,8 @@ const ( TBLTPStats = "tp_stats" TBLTPThresholds = "tp_thresholds" TBLTPFilters = "tp_filters" - TBLSMCosts = "sm_costs" - TBLCDRs = "cdrs" + SMCostsTBL = "sm_costs" + CDRsTBL = "cdrs" TBLVersions = "versions" TIMINGS_CSV = "Timings.csv" DESTINATIONS_CSV = "Destinations.csv" @@ -481,6 +481,7 @@ const ( StatUpdate = "StatUpdate" ResourceUpdate = "ResourceUpdate" CDR = "CDR" + CDRs = "CDRs" ExpiryTime = "ExpiryTime" AllowNegative = "AllowNegative" Disabled = "Disabled" diff --git a/utils/coreutils.go b/utils/coreutils.go index 070e157d3..b957943e3 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -278,6 +278,17 @@ func ParseDurationWithSecs(durStr string) (d time.Duration, err error) { return time.ParseDuration(durStr) } +// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits +func ParseDurationWithNanosecs(durStr string) (d time.Duration, err error) { + if durStr == "" { + return + } + if _, err = strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered + durStr += "ns" + } + return time.ParseDuration(durStr) +} + func AccountKey(tenant, account string) string { return fmt.Sprintf("%s:%s", tenant, account) } From 75fe09e4dc69ce55a4f1af638690679f4dc1fbdc Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 12:53:27 +0200 Subject: [PATCH 02/75] Update integration_tests --- agents/dmtagent_it_test.go | 30 +- apier/v1/apier_it_test.go | 2 +- apier/v1/cdrstatsv1_it_test.go | 8 +- apier/v2/cdrs_it_test.go | 12 +- data/storage/mysql/create_cdrs_tables.sql | 8 +- data/storage/postgres/create_cdrs_tables.sql | 11 +- engine/cdr.go | 4 +- engine/cdr_it_test.go | 2 +- engine/models.go | 2 +- engine/storage_cdrs_it_test.go | 482 +++++++++---------- engine/storage_sql.go | 2 +- engine/stordb_it_test.go | 15 - general_tests/cdrs_onlexp_it_test.go | 5 +- general_tests/tutorial_it_test.go | 88 ++-- 14 files changed, 297 insertions(+), 374 deletions(-) diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index 23515985c..a38257282 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -229,10 +229,10 @@ func TestDmtAgentConnectDiameterClient(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' func TestDmtAgentSendCCRInit(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(0), PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(0), ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -270,10 +270,10 @@ func TestDmtAgentSendCCRInit(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:52:26Z"' func TestDmtAgentSendCCRUpdate(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(300) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(300) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -306,10 +306,10 @@ func TestDmtAgentSendCCRUpdate(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:57:26Z"' func TestDmtAgentSendCCRUpdate2(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(600) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(600) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -341,10 +341,10 @@ func TestDmtAgentSendCCRUpdate2(t *testing.T) { func TestDmtAgentSendCCRTerminate(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(610) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(610) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, true) @@ -535,10 +535,10 @@ func TestDmtAgentSendCCRSMSWrongAccount(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' func TestDmtAgentSendCCRInitWrongAccount(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr4", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr4", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "non_existent", Subject: "non_existent", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr4", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "non_existent", Subject: "non_existent", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(0) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) diff --git a/apier/v1/apier_it_test.go b/apier/v1/apier_it_test.go index a492833af..c33445a81 100644 --- a/apier/v1/apier_it_test.go +++ b/apier/v1/apier_it_test.go @@ -1384,7 +1384,7 @@ func TestApierITGetCdrs(t *testing.T) { func TestApierITProcessCdr(t *testing.T) { var reply string cdr := engine.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_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", + OriginHost: "192.168.1.1", Source: "test", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/apier/v1/cdrstatsv1_it_test.go b/apier/v1/cdrstatsv1_it_test.go index 322087d27..929511d23 100644 --- a/apier/v1/cdrstatsv1_it_test.go +++ b/apier/v1/cdrstatsv1_it_test.go @@ -98,28 +98,28 @@ func TestCDRStatsitPostCdrs(t *testing.T) { storedCdrs := []*engine.CDR{ &engine.CDR{CGRID: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafa", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafb", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafb", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(5) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafc", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafc", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(30) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafd", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafd", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Time{}, RunID: utils.DEFAULT_RUNID, Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/apier/v2/cdrs_it_test.go b/apier/v2/cdrs_it_test.go index 3f604cebb..a75fcece9 100644 --- a/apier/v2/cdrs_it_test.go +++ b/apier/v2/cdrs_it_test.go @@ -117,7 +117,7 @@ func testV2CDRsInjectUnratedCdr(t *testing.T) { } strCdr1 := &engine.CDR{CGRID: utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()), RunID: utils.MetaRaw, ToR: utils.VOICE, OriginID: "bbb1", OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoInjectUnratedCdr", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC), AnswerTime: time.Date(2015, 11, 21, 10, 47, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: -1} @@ -144,7 +144,7 @@ func testV2CDRsProcessCdrRated(t *testing.T) { cdr := &engine.CDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC).String()), RunID: utils.DEFAULT_RUNID, OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRated", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRated", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC), AnswerTime: time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, @@ -162,7 +162,7 @@ func testV2CDRsProcessCdrRaw(t *testing.T) { cdr := &engine.CDR{ CGRID: utils.Sha1("abcdeftg", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, RunID: utils.MetaRaw, ToR: utils.VOICE, OriginID: "abcdeftg", - OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRaw", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRaw", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, @@ -229,19 +229,19 @@ func testV2CDRsProcessPrepaidCdr(t *testing.T) { var reply string cdrs := []*engine.CDR{ &engine.CDR{CGRID: utils.Sha1("dsafdsaf2", 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: "TestV2CdrsMongoProcessPrepaidCdr1", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr1", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, }, &engine.CDR{CGRID: utils.Sha1("abcdeftg2", 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: "TestV2CdrsMongoProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("aererfddf2", 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: "TestV2CdrsMongoProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql index 4423044ec..5f0b2b673 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 char(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 char(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 9b5c9c4fe..d144f9890 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 CHAR(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 CHAR(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,14 +47,13 @@ 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; CREATE INDEX run_origin_smcost_idx ON sm_costs (run_id, origin_id); DROP INDEX IF EXISTS deleted_at_smcost_idx; CREATE INDEX deleted_at_smcost_idx ON sm_costs (deleted_at); - diff --git a/engine/cdr.go b/engine/cdr.go index d2fbd3a97..241212fe7 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -761,7 +761,7 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck // AsCDRsTBL converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { cdrSql = new(CDRsql) - cdrSql.CGRID = cdr.CGRID + cdrSql.Cgrid = cdr.CGRID cdrSql.RunID = cdr.RunID cdrSql.OriginHost = cdr.OriginHost cdrSql.Source = cdr.Source @@ -788,7 +788,7 @@ func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { // NewCDRFromSQL converts the CDRsql into CDR func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr = new(CDR) - cdr.CGRID = cdrSql.CGRID + cdr.CGRID = cdrSql.Cgrid cdr.RunID = cdrSql.RunID cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source diff --git a/engine/cdr_it_test.go b/engine/cdr_it_test.go index f1989e99b..6975abe7f 100644 --- a/engine/cdr_it_test.go +++ b/engine/cdr_it_test.go @@ -36,7 +36,7 @@ func TestHttpJsonPost(t *testing.T) { cdrOut := &ExternalCDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", - Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "account1", Subject: "tgooiscs0014", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String(), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String(), RunID: utils.DEFAULT_RUNID, diff --git a/engine/models.go b/engine/models.go index b123d13c0..bab45b5b0 100755 --- a/engine/models.go +++ b/engine/models.go @@ -464,7 +464,7 @@ type TpFilter struct { type CDRsql struct { ID int64 - CGRID string + Cgrid string RunID string OriginHost string Source string diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go index 4483b8eae..912fdc408 100644 --- a/engine/storage_cdrs_it_test.go +++ b/engine/storage_cdrs_it_test.go @@ -90,28 +90,24 @@ func testSetCDR(cfg *config.CGRConfig) error { return err } rawCDR := &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OrderID: time.Now().UnixNano(), - OriginHost: "127.0.0.1", - Source: "testSetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - Cost: -1, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OrderID: time.Now().UnixNano(), + OriginHost: "127.0.0.1", + Source: "testSetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + Cost: -1, } if err := cdrStorage.SetCDR(rawCDR, false); err != nil { return fmt.Errorf("rawCDR: %+v, SetCDR err: %s", rawCDR, err.Error()) @@ -122,28 +118,24 @@ func testSetCDR(cfg *config.CGRConfig) error { return fmt.Errorf("rawCDR %+v, Unexpected number of CDRs returned: %d", rawCDR, len(cdrs)) } ratedCDR := &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testSetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testSetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testSetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testSetCDRs", + Cost: 0.17, } if err := cdrStorage.SetCDR(ratedCDR, false); err != nil { return fmt.Errorf("ratedCDR: %+v, SetCDR err: %s", ratedCDR, err.Error()) @@ -253,245 +245,205 @@ func testGetCDRs(cfg *config.CGRConfig) error { } cdrs := []*CDR{ &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testGetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testGetCDRs", + Cost: 0.17, }, &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: "run2", - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call_derived", - Account: "1001", - Subject: "1002", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testGetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: "run2", + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call_derived", + Account: "1001", + Subject: "1002", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testGetCDRs", + Cost: 0.17, }, &CDR{ - CGRID: utils.Sha1("testevent2", time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.12", - Source: "testGetCDRs", - OriginID: "testevent2", - ToR: utils.VOICE, - RequestType: utils.META_POSTPAID, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(10) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 29, 12, 59, 0, 0, time.UTC), - Usage: time.Duration(0) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NO_ANSWER", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "rater1", - Cost: 0, + CGRID: utils.Sha1("testevent2", time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.12", + Source: "testGetCDRs", + OriginID: "testevent2", + ToR: utils.VOICE, + RequestType: utils.META_POSTPAID, + Tenant: "itsyscom.com", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 29, 12, 59, 0, 0, time.UTC), + Usage: time.Duration(0) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "rater1", + Cost: 0, }, &CDR{ - CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "192.168.1.13", - Source: "testGetCDRs3", - OriginID: "testevent3", - ToR: utils.VOICE, - RequestType: utils.META_PSEUDOPREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1002", - Subject: "1002", - Destination: "1003", - SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), - Usage: time.Duration(125) * time.Second, - Supplier: "SUPPLIER2", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "192.168.1.13", + Source: "testGetCDRs3", + OriginID: "testevent3", + ToR: utils.VOICE, + RequestType: utils.META_PSEUDOPREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1002", + Subject: "1002", + Destination: "1003", + SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), + Usage: time.Duration(125) * time.Second, + ExtraFields: map[string]string{}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.13", - Source: "testGetCDRs3", - OriginID: "testevent3", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1002", - Subject: "1002", - Destination: "1003", - SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), - Usage: time.Duration(125) * time.Second, - Supplier: "SUPPLIER2", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{}, - CostSource: "testSetCDRs", - Cost: -1, - ExtraInfo: "AccountNotFound", + CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.13", + Source: "testGetCDRs3", + OriginID: "testevent3", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call", + Account: "1002", + Subject: "1002", + Destination: "1003", + SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), + Usage: time.Duration(125) * time.Second, + ExtraFields: map[string]string{}, + CostSource: "testSetCDRs", + Cost: -1, + ExtraInfo: "AccountNotFound", }, &CDR{ - CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "192.168.1.14", - Source: "testGetCDRs", - OriginID: "testevent4", - ToR: utils.VOICE, - RequestType: utils.META_PSEUDOPREPAID, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1003", - Subject: "1003", - Destination: "1007", - SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(2) * time.Second, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(64) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "192.168.1.14", + Source: "testGetCDRs", + OriginID: "testevent4", + ToR: utils.VOICE, + RequestType: utils.META_PSEUDOPREPAID, + Tenant: "itsyscom.com", + Category: "call", + Account: "1003", + Subject: "1003", + Destination: "1007", + SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(64) * time.Second, + ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.14", - Source: "testGetCDRs", - OriginID: "testevent4", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1003", - Subject: "1003", - Destination: "1007", - SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(2) * time.Second, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(64) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, - CostSource: "testSetCDRs", - Cost: 1.205, + CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.14", + Source: "testGetCDRs", + OriginID: "testevent4", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "itsyscom.com", + Category: "call", + Account: "1003", + Subject: "1003", + Destination: "1007", + SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(64) * time.Second, + ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, + CostSource: "testSetCDRs", + Cost: 1.205, }, &CDR{ - CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "127.0.0.1", - Source: "testGetCDRs5", - OriginID: "testevent5", - ToR: utils.SMS, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "sms", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - PDD: time.Duration(0), - AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - Usage: time.Duration(1) * time.Second, - Supplier: "SUPPLIER3", - DisconnectCause: "SENT_OK", - ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "127.0.0.1", + Source: "testGetCDRs5", + OriginID: "testevent5", + ToR: utils.SMS, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "sms", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + Usage: time.Duration(1) * time.Second, + ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testGetCDRs5", - OriginID: "testevent5", - ToR: utils.SMS, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "sms", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - PDD: time.Duration(0), - AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - Usage: time.Duration(1) * time.Second, - Supplier: "SUPPLIER3", - DisconnectCause: "SENT_OK", - ExtraFields: map[string]string{"Service-Context-Id": "voice2@huawei.com"}, - CostSource: "rater", - Cost: 0.15, + CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testGetCDRs5", + OriginID: "testevent5", + ToR: utils.SMS, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "sms", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + Usage: time.Duration(1) * time.Second, + ExtraFields: map[string]string{"Service-Context-Id": "voice2@huawei.com"}, + CostSource: "rater", + Cost: 0.15, }, } // Store all CDRs diff --git a/engine/storage_sql.go b/engine/storage_sql.go index cb90a015d..13e1d4dd2 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -762,7 +762,7 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { } tx = self.db.Begin() cdrSql.UpdatedAt = time.Now() - updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) + updated := tx.Model(&CDRsql{}).Where(&CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) if updated.Error != nil { tx.Rollback() return updated.Error diff --git a/engine/stordb_it_test.go b/engine/stordb_it_test.go index 82fada23d..3d600a3bc 100755 --- a/engine/stordb_it_test.go +++ b/engine/stordb_it_test.go @@ -1677,9 +1677,6 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(reflect.DeepEqual(snd[0].RequestType, rcv[0].RequestType) || reflect.DeepEqual(snd[0].RequestType, rcv[1].RequestType)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].RequestType, rcv[0].RequestType, rcv[1].RequestType) } - if !(reflect.DeepEqual(snd[0].Direction, rcv[0].Direction) || reflect.DeepEqual(snd[0].Direction, rcv[1].Direction)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Direction, rcv[0].Direction, rcv[1].Direction) - } if !(reflect.DeepEqual(snd[0].Tenant, rcv[0].Tenant) || reflect.DeepEqual(snd[0].Tenant, rcv[1].Tenant)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Tenant, rcv[0].Tenant, rcv[1].Tenant) } @@ -1698,21 +1695,12 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(snd[0].SetupTime.Equal(rcv[0].SetupTime) || snd[0].SetupTime.Equal(rcv[1].SetupTime)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].SetupTime, rcv[0].SetupTime, rcv[1].SetupTime) } - if !(reflect.DeepEqual(snd[0].PDD, rcv[0].PDD) || reflect.DeepEqual(snd[0].PDD, rcv[1].PDD)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].PDD, rcv[0].PDD, rcv[1].PDD) - } if !(snd[0].AnswerTime.Equal(rcv[0].AnswerTime) || snd[0].AnswerTime.Equal(rcv[1].AnswerTime)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].AnswerTime, rcv[0].AnswerTime, rcv[1].AnswerTime) } if !(reflect.DeepEqual(snd[0].Usage, rcv[0].Usage) || reflect.DeepEqual(snd[0].Usage, rcv[1].Usage)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Usage, rcv[0].Usage, rcv[1].Usage) } - if !(reflect.DeepEqual(snd[0].Supplier, rcv[0].Supplier) || reflect.DeepEqual(snd[0].Supplier, rcv[1].Supplier)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Supplier, rcv[0].Supplier, rcv[1].Supplier) - } - if !(reflect.DeepEqual(snd[0].DisconnectCause, rcv[0].DisconnectCause) || reflect.DeepEqual(snd[0].DisconnectCause, rcv[1].DisconnectCause)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].DisconnectCause, rcv[0].DisconnectCause, rcv[1].DisconnectCause) - } if !(reflect.DeepEqual(snd[0].ExtraFields, rcv[0].ExtraFields) || reflect.DeepEqual(snd[0].ExtraFields, rcv[1].ExtraFields)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].ExtraFields, rcv[0].ExtraFields, rcv[1].ExtraFields) } @@ -1725,9 +1713,6 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(reflect.DeepEqual(snd[0].CostDetails, rcv[0].CostDetails) || reflect.DeepEqual(snd[0].CostDetails, rcv[1].CostDetails)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].CostDetails, rcv[0].CostDetails, rcv[1].CostDetails) } - if !(reflect.DeepEqual(snd[0].AccountSummary, rcv[0].AccountSummary) || reflect.DeepEqual(snd[0].AccountSummary, rcv[1].AccountSummary)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].AccountSummary, rcv[0].AccountSummary, rcv[1].AccountSummary) - } if !(reflect.DeepEqual(snd[0].ExtraInfo, rcv[0].ExtraInfo) || reflect.DeepEqual(snd[0].ExtraInfo, rcv[1].ExtraInfo)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].ExtraInfo, rcv[0].ExtraInfo, rcv[1].ExtraInfo) } diff --git a/general_tests/cdrs_onlexp_it_test.go b/general_tests/cdrs_onlexp_it_test.go index 9c674cc6b..3e98febc4 100644 --- a/general_tests/cdrs_onlexp_it_test.go +++ b/general_tests/cdrs_onlexp_it_test.go @@ -93,7 +93,7 @@ func TestCDRsOnExpHttpCdrReplication(t *testing.T) { } testCdr1 := &engine.CDR{CGRID: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "httpjsonrpc1", OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} @@ -125,7 +125,6 @@ func TestCDRsOnExpHttpCdrReplication(t *testing.T) { rcvedCdrs[0].ToR != testCdr1.ToR || rcvedCdrs[0].OriginHost != testCdr1.OriginHost || rcvedCdrs[0].RequestType != testCdr1.RequestType || - rcvedCdrs[0].Direction != testCdr1.Direction || rcvedCdrs[0].Tenant != testCdr1.Tenant || rcvedCdrs[0].Category != testCdr1.Category || rcvedCdrs[0].Account != testCdr1.Account || @@ -182,7 +181,7 @@ func TestCDRsOnExpAMQPReplication(t *testing.T) { time.Sleep(time.Duration(5 * time.Second)) testCdr := &engine.CDR{CGRID: utils.Sha1("amqpreconnect", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "amqpreconnect", OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index 79d3325b5..008b387ae 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -498,7 +498,6 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { OriginID: "testevent1", OriginHost: "127.0.0.1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1004", @@ -507,7 +506,6 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { SetupTime: tStart, AnswerTime: tStart, Usage: time.Duration(120) * time.Second, - Supplier: "suppl1", Cost: -1, } var maxTime float64 @@ -520,7 +518,7 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { // Check MaxUsage func TestTutITMaxUsage(t *testing.T) { - setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -530,7 +528,7 @@ func TestTutITMaxUsage(t *testing.T) { } else if maxTime != 1 { t.Errorf("Calling ApierV2.MaxUsage got maxTime: %f", maxTime) } - setupReq = &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq = &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "test_max_usage", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", } @@ -543,7 +541,7 @@ func TestTutITMaxUsage(t *testing.T) { // Check DebitUsage func TestTutITDebitUsage(t *testing.T) { - setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", AnswerTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -558,10 +556,10 @@ func TestTutITDebitUsage(t *testing.T) { // Test CDR from external sources func TestTutITProcessExternalCdr(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "testextcdr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", Supplier: "SUPPL1", + OriginID: "testextcdr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr, &reply); err != nil { @@ -574,10 +572,9 @@ func TestTutITProcessExternalCdr(t *testing.T) { // Test CDR involving UserProfile func TestTutITProcessExternalCdrUP(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, Direction: utils.OUT, - RequestType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", Supplier: "SUPPL1", - SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, + RequestType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", + SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "2", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": utils.USERS}, } var reply string @@ -589,10 +586,10 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { time.Sleep(time.Duration(*waitRater) * time.Millisecond) eCdr := &engine.ExternalCDR{CGRID: "63a8d2bfeca2cfb790826c3ec461696d6574cfde", OrderID: 2, ToR: utils.VOICE, - OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", Supplier: "SUPPL1", - SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), - Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", + SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), + AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), Usage: "2", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": "danb4"}, RunID: utils.DEFAULT_RUNID, Cost: 1} var cdrs []*engine.ExternalCDR @@ -629,33 +626,24 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { if cdrs[0].Destination != eCdr.Destination { t.Errorf("Unexpected Destination for CDR: %+v", cdrs[0]) } - if cdrs[0].Supplier != eCdr.Supplier { - t.Errorf("Unexpected Supplier for CDR: %+v", cdrs[0]) - } if cdrs[0].SetupTime != eCdr.SetupTime { t.Errorf("Unexpected SetupTime for CDR: %+v", cdrs[0]) } - if cdrs[0].PDD != eCdr.PDD { - t.Errorf("Unexpected PDD for CDR: %+v", cdrs[0]) - } if cdrs[0].AnswerTime != eCdr.AnswerTime { t.Errorf("Unexpected AnswerTime for CDR: %+v", cdrs[0]) } if cdrs[0].Usage != eCdr.Usage { t.Errorf("Unexpected Usage for CDR: %+v", cdrs[0]) } - if cdrs[0].DisconnectCause != eCdr.DisconnectCause { - t.Errorf("Unexpected DisconnectCause for CDR: %+v", cdrs[0]) - } } } func TestTutITCostErrors(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "2001", Subject: "2001", Destination: "1001", Supplier: "SUPPL1", + OriginID: "TestTutIT_1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "fake", Account: "2001", Subject: "2001", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr, &reply); err != nil { @@ -679,10 +667,10 @@ func TestTutITCostErrors(t *testing.T) { } } cdr2 := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "2002", Subject: "2002", Destination: "1001", Supplier: "SUPPL1", + OriginID: "TestTutIT_2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, + Tenant: "cgrates.org", Category: "fake", Account: "2002", Subject: "2002", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr2, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -704,10 +692,10 @@ func TestTutITCostErrors(t *testing.T) { } } cdr3 := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_3", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "1001", Subject: "1001", Destination: "2002", Supplier: "SUPPL1", + OriginID: "TestTutIT_3", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, + Tenant: "cgrates.org", Category: "fake", Account: "1001", Subject: "1001", Destination: "2002", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr3, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -959,15 +947,15 @@ func TestTutITLcrQos(t *testing.T) { // Post some CDRs to influence stats testCdr1 := &engine.CDR{CGRID: utils.Sha1("testcdr1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr1", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(2) * time.Minute, Supplier: "suppl1", + Usage: time.Duration(2) * time.Minute, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} testCdr2 := &engine.CDR{CGRID: utils.Sha1("testcdr2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr2", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1003", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl2", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string for _, cdr := range []*engine.CDR{testCdr1, testCdr2} { @@ -998,9 +986,9 @@ func TestTutITLcrQos(t *testing.T) { } testCdr3 := &engine.CDR{CGRID: utils.Sha1("testcdr3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr3", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(180) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(180) * time.Second} if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr3, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -1061,9 +1049,9 @@ func TestTutITLcrQosThreshold(t *testing.T) { } testCdr4 := &engine.CDR{CGRID: utils.Sha1("testcdr4", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr4", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(60) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(60) * time.Second} var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr4, &reply); err != nil { // Should drop ACD under the 2m required by threshold, removing suppl2 from lcr t.Error("Unexpected error: ", err.Error()) @@ -1126,9 +1114,9 @@ func TestTutITLcrQosThreshold(t *testing.T) { } testCdr5 := &engine.CDR{CGRID: utils.Sha1("testcdr5", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr5", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(1) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(1) * time.Second} if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr5, &reply); err != nil { // Should drop ACD under the 1m required by threshold, removing suppl2 from lcr t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -1302,9 +1290,9 @@ func TestTutITCdrStatsAfter(t *testing.T) { func TestTutITPrepaidCDRWithSMCost(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testprepaid1", time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testprepaid1", OriginHost: "192.168.1.1", Source: "TEST_PREPAID_CDR_SMCOST1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC), AnswerTime: time.Date(2016, 4, 6, 13, 30, 0, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl1", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} smCost := &engine.SMCost{CGRID: cdr.CGRID, RunID: utils.META_DEFAULT, @@ -1359,9 +1347,9 @@ func TestTutITPrepaidCDRWithSMCost(t *testing.T) { func TestTutITPrepaidCDRWithoutSMCost(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testprepaid2", time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testprepaid2", OriginHost: "192.168.1.1", Source: "TEST_PREPAID_CDR_NO_SMCOST1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC), AnswerTime: time.Date(2016, 4, 6, 13, 30, 0, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl1", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", cdr, &reply); err != nil { @@ -1390,9 +1378,9 @@ func TestTutITPrepaidCDRWithoutSMCost(t *testing.T) { func TestTutITExportCDR(t *testing.T) { cdr := &engine.CDR{ToR: utils.VOICE, OriginID: "testexportcdr1", OriginHost: "192.168.1.1", Source: "TestTutITExportCDR", RequestType: utils.META_RATED, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 11, 30, 17, 5, 24, 0, time.UTC), AnswerTime: time.Date(2016, 11, 30, 17, 6, 4, 0, time.UTC), - Usage: time.Duration(98) * time.Second, Supplier: "suppl1", + Usage: time.Duration(98) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} cdr.ComputeCGRID() var reply string From 10a8d02d36a61219da91d53bf9a3c0ca9be99a5e Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 12:53:27 +0200 Subject: [PATCH 03/75] Update integration_tests --- agents/dmtagent_it_test.go | 30 +- apier/v1/apier_it_test.go | 2 +- apier/v1/cdrstatsv1_it_test.go | 8 +- apier/v2/cdrs_it_test.go | 12 +- data/storage/mysql/create_cdrs_tables.sql | 8 +- data/storage/postgres/create_cdrs_tables.sql | 11 +- engine/cdr.go | 4 +- engine/cdr_it_test.go | 2 +- engine/models.go | 2 +- engine/storage_cdrs_it_test.go | 482 +++++++++---------- engine/storage_sql.go | 2 +- engine/stordb_it_test.go | 15 - general_tests/cdrs_onlexp_it_test.go | 5 +- general_tests/tutorial_it_test.go | 88 ++-- 14 files changed, 297 insertions(+), 374 deletions(-) diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index 23515985c..a38257282 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -229,10 +229,10 @@ func TestDmtAgentConnectDiameterClient(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' func TestDmtAgentSendCCRInit(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(0), PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(0), ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -270,10 +270,10 @@ func TestDmtAgentSendCCRInit(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:52:26Z"' func TestDmtAgentSendCCRUpdate(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(300) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(300) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -306,10 +306,10 @@ func TestDmtAgentSendCCRUpdate(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:57:26Z"' func TestDmtAgentSendCCRUpdate2(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(600) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(600) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -341,10 +341,10 @@ func TestDmtAgentSendCCRUpdate2(t *testing.T) { func TestDmtAgentSendCCRTerminate(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(610) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(610) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, true) @@ -535,10 +535,10 @@ func TestDmtAgentSendCCRSMSWrongAccount(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' func TestDmtAgentSendCCRInitWrongAccount(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testccr4", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr4", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", - Tenant: "cgrates.org", Category: "call", Account: "non_existent", Subject: "non_existent", Destination: "1004", Supplier: "SUPPL1", + OriginID: "testccr4", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "non_existent", Subject: "non_existent", Destination: "1004", SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(0) * time.Second, PDD: time.Duration(7) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) diff --git a/apier/v1/apier_it_test.go b/apier/v1/apier_it_test.go index a492833af..c33445a81 100644 --- a/apier/v1/apier_it_test.go +++ b/apier/v1/apier_it_test.go @@ -1384,7 +1384,7 @@ func TestApierITGetCdrs(t *testing.T) { func TestApierITProcessCdr(t *testing.T) { var reply string cdr := engine.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_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", + OriginHost: "192.168.1.1", Source: "test", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/apier/v1/cdrstatsv1_it_test.go b/apier/v1/cdrstatsv1_it_test.go index 322087d27..929511d23 100644 --- a/apier/v1/cdrstatsv1_it_test.go +++ b/apier/v1/cdrstatsv1_it_test.go @@ -98,28 +98,28 @@ func TestCDRStatsitPostCdrs(t *testing.T) { storedCdrs := []*engine.CDR{ &engine.CDR{CGRID: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafa", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafb", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafb", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(5) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafc", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafc", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(30) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("dsafdsafd", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafd", OriginHost: "192.168.1.1", Source: "test", - RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Time{}, RunID: utils.DEFAULT_RUNID, Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/apier/v2/cdrs_it_test.go b/apier/v2/cdrs_it_test.go index 3f604cebb..a75fcece9 100644 --- a/apier/v2/cdrs_it_test.go +++ b/apier/v2/cdrs_it_test.go @@ -117,7 +117,7 @@ func testV2CDRsInjectUnratedCdr(t *testing.T) { } strCdr1 := &engine.CDR{CGRID: utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()), RunID: utils.MetaRaw, ToR: utils.VOICE, OriginID: "bbb1", OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoInjectUnratedCdr", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC), AnswerTime: time.Date(2015, 11, 21, 10, 47, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: -1} @@ -144,7 +144,7 @@ func testV2CDRsProcessCdrRated(t *testing.T) { cdr := &engine.CDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC).String()), RunID: utils.DEFAULT_RUNID, OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRated", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRated", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC), AnswerTime: time.Date(2015, 12, 13, 18, 15, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, @@ -162,7 +162,7 @@ func testV2CDRsProcessCdrRaw(t *testing.T) { cdr := &engine.CDR{ CGRID: utils.Sha1("abcdeftg", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, RunID: utils.MetaRaw, ToR: utils.VOICE, OriginID: "abcdeftg", - OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRaw", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessCdrRaw", RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, @@ -229,19 +229,19 @@ func testV2CDRsProcessPrepaidCdr(t *testing.T) { var reply string cdrs := []*engine.CDR{ &engine.CDR{CGRID: utils.Sha1("dsafdsaf2", 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: "TestV2CdrsMongoProcessPrepaidCdr1", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr1", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, }, &engine.CDR{CGRID: utils.Sha1("abcdeftg2", 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: "TestV2CdrsMongoProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, &engine.CDR{CGRID: utils.Sha1("aererfddf2", 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: "TestV2CdrsMongoProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + OriginHost: "192.168.1.1", Source: "TestV2CdrsMongoProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql index 4423044ec..5f0b2b673 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 char(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 char(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 9b5c9c4fe..d144f9890 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 CHAR(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 CHAR(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,14 +47,13 @@ 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; CREATE INDEX run_origin_smcost_idx ON sm_costs (run_id, origin_id); DROP INDEX IF EXISTS deleted_at_smcost_idx; CREATE INDEX deleted_at_smcost_idx ON sm_costs (deleted_at); - diff --git a/engine/cdr.go b/engine/cdr.go index d2fbd3a97..241212fe7 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -761,7 +761,7 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck // AsCDRsTBL converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { cdrSql = new(CDRsql) - cdrSql.CGRID = cdr.CGRID + cdrSql.Cgrid = cdr.CGRID cdrSql.RunID = cdr.RunID cdrSql.OriginHost = cdr.OriginHost cdrSql.Source = cdr.Source @@ -788,7 +788,7 @@ func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { // NewCDRFromSQL converts the CDRsql into CDR func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr = new(CDR) - cdr.CGRID = cdrSql.CGRID + cdr.CGRID = cdrSql.Cgrid cdr.RunID = cdrSql.RunID cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source diff --git a/engine/cdr_it_test.go b/engine/cdr_it_test.go index f1989e99b..6975abe7f 100644 --- a/engine/cdr_it_test.go +++ b/engine/cdr_it_test.go @@ -36,7 +36,7 @@ func TestHttpJsonPost(t *testing.T) { cdrOut := &ExternalCDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", - Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "account1", Subject: "tgooiscs0014", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String(), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String(), RunID: utils.DEFAULT_RUNID, diff --git a/engine/models.go b/engine/models.go index b123d13c0..bab45b5b0 100755 --- a/engine/models.go +++ b/engine/models.go @@ -464,7 +464,7 @@ type TpFilter struct { type CDRsql struct { ID int64 - CGRID string + Cgrid string RunID string OriginHost string Source string diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go index 4483b8eae..912fdc408 100644 --- a/engine/storage_cdrs_it_test.go +++ b/engine/storage_cdrs_it_test.go @@ -90,28 +90,24 @@ func testSetCDR(cfg *config.CGRConfig) error { return err } rawCDR := &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OrderID: time.Now().UnixNano(), - OriginHost: "127.0.0.1", - Source: "testSetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - Cost: -1, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OrderID: time.Now().UnixNano(), + OriginHost: "127.0.0.1", + Source: "testSetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + Cost: -1, } if err := cdrStorage.SetCDR(rawCDR, false); err != nil { return fmt.Errorf("rawCDR: %+v, SetCDR err: %s", rawCDR, err.Error()) @@ -122,28 +118,24 @@ func testSetCDR(cfg *config.CGRConfig) error { return fmt.Errorf("rawCDR %+v, Unexpected number of CDRs returned: %d", rawCDR, len(cdrs)) } ratedCDR := &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testSetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testSetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testSetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testSetCDRs", + Cost: 0.17, } if err := cdrStorage.SetCDR(ratedCDR, false); err != nil { return fmt.Errorf("ratedCDR: %+v, SetCDR err: %s", ratedCDR, err.Error()) @@ -253,245 +245,205 @@ func testGetCDRs(cfg *config.CGRConfig) error { } cdrs := []*CDR{ &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testGetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testGetCDRs", + Cost: 0.17, }, &CDR{ - CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), - RunID: "run2", - OriginHost: "127.0.0.1", - Source: "testGetCDRs", - OriginID: "testevent1", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call_derived", - Account: "1001", - Subject: "1002", - Destination: "1002", - SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(35) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "testGetCDRs", - Cost: 0.17, + CGRID: utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + RunID: "run2", + OriginHost: "127.0.0.1", + Source: "testGetCDRs", + OriginID: "testevent1", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call_derived", + Account: "1001", + Subject: "1002", + Destination: "1002", + SetupTime: time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(35) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "testGetCDRs", + Cost: 0.17, }, &CDR{ - CGRID: utils.Sha1("testevent2", time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.12", - Source: "testGetCDRs", - OriginID: "testevent2", - ToR: utils.VOICE, - RequestType: utils.META_POSTPAID, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1004", - Subject: "1004", - Destination: "1007", - SetupTime: time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(10) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 29, 12, 59, 0, 0, time.UTC), - Usage: time.Duration(0) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NO_ANSWER", - ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, - CostSource: "rater1", - Cost: 0, + CGRID: utils.Sha1("testevent2", time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.12", + Source: "testGetCDRs", + OriginID: "testevent2", + ToR: utils.VOICE, + RequestType: utils.META_POSTPAID, + Tenant: "itsyscom.com", + Category: "call", + Account: "1004", + Subject: "1004", + Destination: "1007", + SetupTime: time.Date(2015, 12, 29, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 29, 12, 59, 0, 0, time.UTC), + Usage: time.Duration(0) * time.Second, + ExtraFields: map[string]string{"ExtraHeader1": "ExtraVal1", "ExtraHeader2": "ExtraVal2"}, + CostSource: "rater1", + Cost: 0, }, &CDR{ - CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "192.168.1.13", - Source: "testGetCDRs3", - OriginID: "testevent3", - ToR: utils.VOICE, - RequestType: utils.META_PSEUDOPREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1002", - Subject: "1002", - Destination: "1003", - SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), - Usage: time.Duration(125) * time.Second, - Supplier: "SUPPLIER2", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "192.168.1.13", + Source: "testGetCDRs3", + OriginID: "testevent3", + ToR: utils.VOICE, + RequestType: utils.META_PSEUDOPREPAID, + Tenant: "cgrates.org", + Category: "call", + Account: "1002", + Subject: "1002", + Destination: "1003", + SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), + Usage: time.Duration(125) * time.Second, + ExtraFields: map[string]string{}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.13", - Source: "testGetCDRs3", - OriginID: "testevent3", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "call", - Account: "1002", - Subject: "1002", - Destination: "1003", - SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), - PDD: time.Duration(20) * time.Millisecond, - AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), - Usage: time.Duration(125) * time.Second, - Supplier: "SUPPLIER2", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{}, - CostSource: "testSetCDRs", - Cost: -1, - ExtraInfo: "AccountNotFound", + CGRID: utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.13", + Source: "testGetCDRs3", + OriginID: "testevent3", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call", + Account: "1002", + Subject: "1002", + Destination: "1003", + SetupTime: time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 28, 12, 58, 30, 0, time.UTC), + Usage: time.Duration(125) * time.Second, + ExtraFields: map[string]string{}, + CostSource: "testSetCDRs", + Cost: -1, + ExtraInfo: "AccountNotFound", }, &CDR{ - CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "192.168.1.14", - Source: "testGetCDRs", - OriginID: "testevent4", - ToR: utils.VOICE, - RequestType: utils.META_PSEUDOPREPAID, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1003", - Subject: "1003", - Destination: "1007", - SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(2) * time.Second, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(64) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "192.168.1.14", + Source: "testGetCDRs", + OriginID: "testevent4", + ToR: utils.VOICE, + RequestType: utils.META_PSEUDOPREPAID, + Tenant: "itsyscom.com", + Category: "call", + Account: "1003", + Subject: "1003", + Destination: "1007", + SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(64) * time.Second, + ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "192.168.1.14", - Source: "testGetCDRs", - OriginID: "testevent4", - ToR: utils.VOICE, - RequestType: utils.META_RATED, - Direction: utils.OUT, - Tenant: "itsyscom.com", - Category: "call", - Account: "1003", - Subject: "1003", - Destination: "1007", - SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), - PDD: time.Duration(2) * time.Second, - AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), - Usage: time.Duration(64) * time.Second, - Supplier: "SUPPLIER1", - DisconnectCause: "NORMAL_DISCONNECT", - ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, - CostSource: "testSetCDRs", - Cost: 1.205, + CGRID: utils.Sha1("testevent4", time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "192.168.1.14", + Source: "testGetCDRs", + OriginID: "testevent4", + ToR: utils.VOICE, + RequestType: utils.META_RATED, + Tenant: "itsyscom.com", + Category: "call", + Account: "1003", + Subject: "1003", + Destination: "1007", + SetupTime: time.Date(2015, 12, 14, 14, 52, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 12, 14, 52, 20, 0, time.UTC), + Usage: time.Duration(64) * time.Second, + ExtraFields: map[string]string{"ExtraHeader3": "ExtraVal3"}, + CostSource: "testSetCDRs", + Cost: 1.205, }, &CDR{ - CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), - RunID: utils.MetaRaw, - OriginHost: "127.0.0.1", - Source: "testGetCDRs5", - OriginID: "testevent5", - ToR: utils.SMS, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "sms", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - PDD: time.Duration(0), - AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - Usage: time.Duration(1) * time.Second, - Supplier: "SUPPLIER3", - DisconnectCause: "SENT_OK", - ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, - CostSource: "", - Cost: -1, + CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), + RunID: utils.MetaRaw, + OriginHost: "127.0.0.1", + Source: "testGetCDRs5", + OriginID: "testevent5", + ToR: utils.SMS, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "sms", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + Usage: time.Duration(1) * time.Second, + ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + CostSource: "", + Cost: -1, }, &CDR{ - CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), - RunID: utils.META_DEFAULT, - OriginHost: "127.0.0.1", - Source: "testGetCDRs5", - OriginID: "testevent5", - ToR: utils.SMS, - RequestType: utils.META_PREPAID, - Direction: utils.OUT, - Tenant: "cgrates.org", - Category: "sms", - Account: "1001", - Subject: "1001", - Destination: "1002", - SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - PDD: time.Duration(0), - AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), - Usage: time.Duration(1) * time.Second, - Supplier: "SUPPLIER3", - DisconnectCause: "SENT_OK", - ExtraFields: map[string]string{"Service-Context-Id": "voice2@huawei.com"}, - CostSource: "rater", - Cost: 0.15, + CGRID: utils.Sha1("testevent5", time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC).String()), + RunID: utils.META_DEFAULT, + OriginHost: "127.0.0.1", + Source: "testGetCDRs5", + OriginID: "testevent5", + ToR: utils.SMS, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: "sms", + Account: "1001", + Subject: "1001", + Destination: "1002", + SetupTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + AnswerTime: time.Date(2015, 12, 15, 18, 22, 0, 0, time.UTC), + Usage: time.Duration(1) * time.Second, + ExtraFields: map[string]string{"Service-Context-Id": "voice2@huawei.com"}, + CostSource: "rater", + Cost: 0.15, }, } // Store all CDRs diff --git a/engine/storage_sql.go b/engine/storage_sql.go index cb90a015d..13e1d4dd2 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -762,7 +762,7 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { } tx = self.db.Begin() cdrSql.UpdatedAt = time.Now() - updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) + updated := tx.Model(&CDRsql{}).Where(&CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) if updated.Error != nil { tx.Rollback() return updated.Error diff --git a/engine/stordb_it_test.go b/engine/stordb_it_test.go index 82fada23d..3d600a3bc 100755 --- a/engine/stordb_it_test.go +++ b/engine/stordb_it_test.go @@ -1677,9 +1677,6 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(reflect.DeepEqual(snd[0].RequestType, rcv[0].RequestType) || reflect.DeepEqual(snd[0].RequestType, rcv[1].RequestType)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].RequestType, rcv[0].RequestType, rcv[1].RequestType) } - if !(reflect.DeepEqual(snd[0].Direction, rcv[0].Direction) || reflect.DeepEqual(snd[0].Direction, rcv[1].Direction)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Direction, rcv[0].Direction, rcv[1].Direction) - } if !(reflect.DeepEqual(snd[0].Tenant, rcv[0].Tenant) || reflect.DeepEqual(snd[0].Tenant, rcv[1].Tenant)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Tenant, rcv[0].Tenant, rcv[1].Tenant) } @@ -1698,21 +1695,12 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(snd[0].SetupTime.Equal(rcv[0].SetupTime) || snd[0].SetupTime.Equal(rcv[1].SetupTime)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].SetupTime, rcv[0].SetupTime, rcv[1].SetupTime) } - if !(reflect.DeepEqual(snd[0].PDD, rcv[0].PDD) || reflect.DeepEqual(snd[0].PDD, rcv[1].PDD)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].PDD, rcv[0].PDD, rcv[1].PDD) - } if !(snd[0].AnswerTime.Equal(rcv[0].AnswerTime) || snd[0].AnswerTime.Equal(rcv[1].AnswerTime)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].AnswerTime, rcv[0].AnswerTime, rcv[1].AnswerTime) } if !(reflect.DeepEqual(snd[0].Usage, rcv[0].Usage) || reflect.DeepEqual(snd[0].Usage, rcv[1].Usage)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Usage, rcv[0].Usage, rcv[1].Usage) } - if !(reflect.DeepEqual(snd[0].Supplier, rcv[0].Supplier) || reflect.DeepEqual(snd[0].Supplier, rcv[1].Supplier)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].Supplier, rcv[0].Supplier, rcv[1].Supplier) - } - if !(reflect.DeepEqual(snd[0].DisconnectCause, rcv[0].DisconnectCause) || reflect.DeepEqual(snd[0].DisconnectCause, rcv[1].DisconnectCause)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].DisconnectCause, rcv[0].DisconnectCause, rcv[1].DisconnectCause) - } if !(reflect.DeepEqual(snd[0].ExtraFields, rcv[0].ExtraFields) || reflect.DeepEqual(snd[0].ExtraFields, rcv[1].ExtraFields)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].ExtraFields, rcv[0].ExtraFields, rcv[1].ExtraFields) } @@ -1725,9 +1713,6 @@ func testStorDBitCRUDCDRs(t *testing.T) { if !(reflect.DeepEqual(snd[0].CostDetails, rcv[0].CostDetails) || reflect.DeepEqual(snd[0].CostDetails, rcv[1].CostDetails)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].CostDetails, rcv[0].CostDetails, rcv[1].CostDetails) } - if !(reflect.DeepEqual(snd[0].AccountSummary, rcv[0].AccountSummary) || reflect.DeepEqual(snd[0].AccountSummary, rcv[1].AccountSummary)) { - t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].AccountSummary, rcv[0].AccountSummary, rcv[1].AccountSummary) - } if !(reflect.DeepEqual(snd[0].ExtraInfo, rcv[0].ExtraInfo) || reflect.DeepEqual(snd[0].ExtraInfo, rcv[1].ExtraInfo)) { t.Errorf("Expecting: %+v, received: %+v || %+v", snd[0].ExtraInfo, rcv[0].ExtraInfo, rcv[1].ExtraInfo) } diff --git a/general_tests/cdrs_onlexp_it_test.go b/general_tests/cdrs_onlexp_it_test.go index 9c674cc6b..3e98febc4 100644 --- a/general_tests/cdrs_onlexp_it_test.go +++ b/general_tests/cdrs_onlexp_it_test.go @@ -93,7 +93,7 @@ func TestCDRsOnExpHttpCdrReplication(t *testing.T) { } testCdr1 := &engine.CDR{CGRID: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "httpjsonrpc1", OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} @@ -125,7 +125,6 @@ func TestCDRsOnExpHttpCdrReplication(t *testing.T) { rcvedCdrs[0].ToR != testCdr1.ToR || rcvedCdrs[0].OriginHost != testCdr1.OriginHost || rcvedCdrs[0].RequestType != testCdr1.RequestType || - rcvedCdrs[0].Direction != testCdr1.Direction || rcvedCdrs[0].Tenant != testCdr1.Tenant || rcvedCdrs[0].Category != testCdr1.Category || rcvedCdrs[0].Account != testCdr1.Account || @@ -182,7 +181,7 @@ func TestCDRsOnExpAMQPReplication(t *testing.T) { time.Sleep(time.Duration(5 * time.Second)) testCdr := &engine.CDR{CGRID: utils.Sha1("amqpreconnect", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "amqpreconnect", OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index 79d3325b5..008b387ae 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -498,7 +498,6 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { OriginID: "testevent1", OriginHost: "127.0.0.1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1004", @@ -507,7 +506,6 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { SetupTime: tStart, AnswerTime: tStart, Usage: time.Duration(120) * time.Second, - Supplier: "suppl1", Cost: -1, } var maxTime float64 @@ -520,7 +518,7 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { // Check MaxUsage func TestTutITMaxUsage(t *testing.T) { - setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -530,7 +528,7 @@ func TestTutITMaxUsage(t *testing.T) { } else if maxTime != 1 { t.Errorf("Calling ApierV2.MaxUsage got maxTime: %f", maxTime) } - setupReq = &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq = &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "test_max_usage", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", } @@ -543,7 +541,7 @@ func TestTutITMaxUsage(t *testing.T) { // Check DebitUsage func TestTutITDebitUsage(t *testing.T) { - setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", AnswerTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -558,10 +556,10 @@ func TestTutITDebitUsage(t *testing.T) { // Test CDR from external sources func TestTutITProcessExternalCdr(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "testextcdr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", Supplier: "SUPPL1", + OriginID: "testextcdr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr, &reply); err != nil { @@ -574,10 +572,9 @@ func TestTutITProcessExternalCdr(t *testing.T) { // Test CDR involving UserProfile func TestTutITProcessExternalCdrUP(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, Direction: utils.OUT, - RequestType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", Supplier: "SUPPL1", - SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, + RequestType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", + SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "2", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": utils.USERS}, } var reply string @@ -589,10 +586,10 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { time.Sleep(time.Duration(*waitRater) * time.Millisecond) eCdr := &engine.ExternalCDR{CGRID: "63a8d2bfeca2cfb790826c3ec461696d6574cfde", OrderID: 2, ToR: utils.VOICE, - OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", Supplier: "SUPPL1", - SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), - Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", + SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), + AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), Usage: "2", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": "danb4"}, RunID: utils.DEFAULT_RUNID, Cost: 1} var cdrs []*engine.ExternalCDR @@ -629,33 +626,24 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { if cdrs[0].Destination != eCdr.Destination { t.Errorf("Unexpected Destination for CDR: %+v", cdrs[0]) } - if cdrs[0].Supplier != eCdr.Supplier { - t.Errorf("Unexpected Supplier for CDR: %+v", cdrs[0]) - } if cdrs[0].SetupTime != eCdr.SetupTime { t.Errorf("Unexpected SetupTime for CDR: %+v", cdrs[0]) } - if cdrs[0].PDD != eCdr.PDD { - t.Errorf("Unexpected PDD for CDR: %+v", cdrs[0]) - } if cdrs[0].AnswerTime != eCdr.AnswerTime { t.Errorf("Unexpected AnswerTime for CDR: %+v", cdrs[0]) } if cdrs[0].Usage != eCdr.Usage { t.Errorf("Unexpected Usage for CDR: %+v", cdrs[0]) } - if cdrs[0].DisconnectCause != eCdr.DisconnectCause { - t.Errorf("Unexpected DisconnectCause for CDR: %+v", cdrs[0]) - } } } func TestTutITCostErrors(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "2001", Subject: "2001", Destination: "1001", Supplier: "SUPPL1", + OriginID: "TestTutIT_1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "fake", Account: "2001", Subject: "2001", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr, &reply); err != nil { @@ -679,10 +667,10 @@ func TestTutITCostErrors(t *testing.T) { } } cdr2 := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "2002", Subject: "2002", Destination: "1001", Supplier: "SUPPL1", + OriginID: "TestTutIT_2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, + Tenant: "cgrates.org", Category: "fake", Account: "2002", Subject: "2002", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr2, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -704,10 +692,10 @@ func TestTutITCostErrors(t *testing.T) { } } cdr3 := &engine.ExternalCDR{ToR: utils.VOICE, - OriginID: "TestTutIT_3", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, - Tenant: "cgrates.org", Category: "fake", Account: "1001", Subject: "1001", Destination: "2002", Supplier: "SUPPL1", + OriginID: "TestTutIT_3", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, + Tenant: "cgrates.org", Category: "fake", Account: "1001", Subject: "1001", Destination: "2002", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "1", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV1.ProcessExternalCdr", cdr3, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -959,15 +947,15 @@ func TestTutITLcrQos(t *testing.T) { // Post some CDRs to influence stats testCdr1 := &engine.CDR{CGRID: utils.Sha1("testcdr1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr1", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(2) * time.Minute, Supplier: "suppl1", + Usage: time.Duration(2) * time.Minute, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} testCdr2 := &engine.CDR{CGRID: utils.Sha1("testcdr2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr2", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1003", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl2", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string for _, cdr := range []*engine.CDR{testCdr1, testCdr2} { @@ -998,9 +986,9 @@ func TestTutITLcrQos(t *testing.T) { } testCdr3 := &engine.CDR{CGRID: utils.Sha1("testcdr3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr3", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(180) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(180) * time.Second} if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr3, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -1061,9 +1049,9 @@ func TestTutITLcrQosThreshold(t *testing.T) { } testCdr4 := &engine.CDR{CGRID: utils.Sha1("testcdr4", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr4", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(60) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(60) * time.Second} var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr4, &reply); err != nil { // Should drop ACD under the 2m required by threshold, removing suppl2 from lcr t.Error("Unexpected error: ", err.Error()) @@ -1126,9 +1114,9 @@ func TestTutITLcrQosThreshold(t *testing.T) { } testCdr5 := &engine.CDR{CGRID: utils.Sha1("testcdr5", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testcdr5", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", + Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1004", SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), - Usage: time.Duration(1) * time.Second, Supplier: "suppl2"} + Usage: time.Duration(1) * time.Second} if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", testCdr5, &reply); err != nil { // Should drop ACD under the 1m required by threshold, removing suppl2 from lcr t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -1302,9 +1290,9 @@ func TestTutITCdrStatsAfter(t *testing.T) { func TestTutITPrepaidCDRWithSMCost(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testprepaid1", time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testprepaid1", OriginHost: "192.168.1.1", Source: "TEST_PREPAID_CDR_SMCOST1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC), AnswerTime: time.Date(2016, 4, 6, 13, 30, 0, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl1", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} smCost := &engine.SMCost{CGRID: cdr.CGRID, RunID: utils.META_DEFAULT, @@ -1359,9 +1347,9 @@ func TestTutITPrepaidCDRWithSMCost(t *testing.T) { func TestTutITPrepaidCDRWithoutSMCost(t *testing.T) { cdr := &engine.CDR{CGRID: utils.Sha1("testprepaid2", time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "testprepaid2", OriginHost: "192.168.1.1", Source: "TEST_PREPAID_CDR_NO_SMCOST1", RequestType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 4, 6, 13, 29, 24, 0, time.UTC), AnswerTime: time.Date(2016, 4, 6, 13, 30, 0, 0, time.UTC), - Usage: time.Duration(90) * time.Second, Supplier: "suppl1", + Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string if err := tutLocalRpc.Call("CdrsV1.ProcessCdr", cdr, &reply); err != nil { @@ -1390,9 +1378,9 @@ func TestTutITPrepaidCDRWithoutSMCost(t *testing.T) { func TestTutITExportCDR(t *testing.T) { cdr := &engine.CDR{ToR: utils.VOICE, OriginID: "testexportcdr1", OriginHost: "192.168.1.1", Source: "TestTutITExportCDR", RequestType: utils.META_RATED, - Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", + Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1003", SetupTime: time.Date(2016, 11, 30, 17, 5, 24, 0, time.UTC), AnswerTime: time.Date(2016, 11, 30, 17, 6, 4, 0, time.UTC), - Usage: time.Duration(98) * time.Second, Supplier: "suppl1", + Usage: time.Duration(98) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} cdr.ComputeCGRID() var reply string From b7fb426b09dd390c5d6a2f8c5e8eb6c2cbed3f3d Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 13:05:02 +0200 Subject: [PATCH 04/75] 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 82be280d0a053990d4ad1849807c52ce7a4c6286 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 13:05:02 +0200 Subject: [PATCH 05/75] 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 06/75] 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 07/75] 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 From d789cac0b768ef1690ed31aba6f82494234ae14b Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 2 Nov 2017 15:33:31 +0100 Subject: [PATCH 08/75] Responder MaxComputedUsage implementation --- apier/v1/debit_test.go | 2 +- cmd/cgr-engine/rater.go | 2 +- engine/responder.go | 50 ++++++++++++++++++++++++++++++++------ engine/responder_test.go | 2 +- general_tests/auth_test.go | 5 ++-- utils/errors.go | 1 + 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/apier/v1/debit_test.go b/apier/v1/debit_test.go index 772b7b06a..460d13751 100644 --- a/apier/v1/debit_test.go +++ b/apier/v1/debit_test.go @@ -37,7 +37,7 @@ var ( func init() { apierDebitStorage, _ = engine.NewMapStorage() cfg, _ := config.NewDefaultCGRConfig() - responder := new(engine.Responder) + responder := &engine.Responder{MaxComputedUsage: cfg.RALsMaxComputedUsage} dm = engine.NewDataManager(apierDebitStorage) engine.SetDataStorage(dm) apierDebit = &ApierV1{ diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index 7994eb181..4090ff227 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -229,7 +229,7 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC for _, chn := range waitTasks { <-chn } - responder := &engine.Responder{ExitChan: exitChan} + responder := &engine.Responder{ExitChan: exitChan, MaxComputedUsage: cfg.RALsMaxComputedUsage} responder.SetTimeToLive(cfg.ResponseCacheTTL, nil) apierRpcV1 := &v1.ApierV1{StorDb: loadDb, DataManager: dm, CdrDb: cdrDb, Config: cfg, Responder: responder, ServManager: serviceManager, diff --git a/engine/responder.go b/engine/responder.go index bfb9d1de5..1057460c1 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -46,12 +46,13 @@ type AttrGetLcr struct { } type Responder struct { - ExitChan chan bool - Stats rpcclient.RpcClientConnection - Timeout time.Duration - Timezone string - cnt int64 - responseCache *cache.ResponseCache + ExitChan chan bool + Stats rpcclient.RpcClientConnection + Timeout time.Duration + Timezone string + MaxComputedUsage map[string]time.Duration + cnt int64 + responseCache *cache.ResponseCache } func (rs *Responder) SetTimeToLive(timeToLive time.Duration, out *int) error { @@ -66,6 +67,18 @@ func (rs *Responder) getCache() *cache.ResponseCache { return rs.responseCache } +// usageAllowed checks requested usage against configured MaxComputedUsage +func (rs *Responder) usageAllowed(tor string, reqUsage time.Duration) (allowed bool) { + mcu, has := rs.MaxComputedUsage[tor] + if !has { + mcu = rs.MaxComputedUsage[utils.ANY] + } + if reqUsage <= mcu { + allowed = true + } + return +} + /* RPC method thet provides the external RPC interface for getting the rating information. */ @@ -91,6 +104,9 @@ func (rs *Responder) GetCost(arg *CallDescriptor, reply *CallCost) (err error) { }, arg, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } r, e := guardian.Guardian.Guard(func() (interface{}, error) { return arg.GetCost() }, 0, arg.GetAccountKey()) @@ -124,6 +140,9 @@ func (rs *Responder) Debit(arg *CallDescriptor, reply *CallCost) (err error) { }, arg, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } r, e := arg.Debit() if e != nil { return e @@ -161,6 +180,9 @@ func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error) }, arg, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } r, e := arg.MaxDebit() if e != nil { rs.getCache().Cache(cacheKey, &cache.CacheItem{ @@ -208,6 +230,9 @@ func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err }) return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } err = arg.RefundIncrements() rs.getCache().Cache(cacheKey, &cache.CacheItem{ Value: reply, @@ -247,6 +272,9 @@ func (rs *Responder) RefundRounding(arg *CallDescriptor, reply *float64) (err er }) return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } err = arg.RefundRounding() rs.getCache().Cache(cacheKey, &cache.CacheItem{ Value: reply, @@ -276,6 +304,9 @@ func (rs *Responder) GetMaxSessionTime(arg *CallDescriptor, reply *float64) (err }, arg, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return err } + if !rs.usageAllowed(arg.TOR, arg.GetDuration()) { + return utils.ErrMaxUsageExceeded + } r, e := arg.GetMaxSessionDuration() *reply, err = float64(r), e return @@ -312,7 +343,9 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { rs.getCache().Cache(cacheKey, &cache.CacheItem{Err: err}) return err } - + if !rs.usageAllowed(ev.ToR, ev.Usage) { + return utils.ErrMaxUsageExceeded + } maxCallDuration := -1.0 attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: utils.OUT, @@ -518,6 +551,9 @@ func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error { rs.getCache().Cache(cacheKey, &cache.CacheItem{Err: err}) return err } + if !rs.usageAllowed(cd.TOR, cd.GetDuration()) { + return utils.ErrMaxUsageExceeded + } lcrCost, err := attrs.CallDescriptor.GetLCR(rs.Stats, attrs.LCRFilter, attrs.Paginator) if err != nil { rs.getCache().Cache(cacheKey, &cache.CacheItem{Err: err}) diff --git a/engine/responder_test.go b/engine/responder_test.go index 567f0f10e..e367761fe 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -33,6 +33,7 @@ var rsponder *Responder func init() { cfg, _ := config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) + rsponder = &Responder{MaxComputedUsage: cfg.RALsMaxComputedUsage} } // Test internal abilites of GetDerivedChargers @@ -40,7 +41,6 @@ func TestResponderGetDerivedChargers(t *testing.T) { cfgedDC := &utils.DerivedChargers{DestinationIDs: utils.StringMap{}, Chargers: []*utils.DerivedCharger{&utils.DerivedCharger{RunID: "responder1", RequestTypeField: utils.META_DEFAULT, DirectionField: "test", TenantField: "test", CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}}} - rsponder = &Responder{} attrs := &utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "responder_test", Subject: "responder_test"} if err := dm.DataDB().SetDerivedChargers(utils.DerivedChargersKey(utils.OUT, utils.ANY, utils.ANY, utils.ANY, utils.ANY), cfgedDC, utils.NonTransactional); err != nil { t.Error(err) diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index 18a3a59dd..2924a89b7 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -35,7 +35,7 @@ func TestAuthSetStorage(t *testing.T) { data, _ := engine.NewMapStorageJson() dbAuth = engine.NewDataManager(data) engine.SetDataStorage(dbAuth) - rsponder = new(engine.Responder) + rsponder = &engine.Responder{MaxComputedUsage: config.CgrConfig().RALsMaxComputedUsage} } @@ -98,7 +98,8 @@ func TestAuthPostpaidNoAcnt(t *testing.T) { Category: "call", Account: "nonexistent", Subject: "testauthpostpaid1", Destination: "4986517174963", SetupTime: time.Date(2015, 8, 27, 11, 26, 0, 0, time.UTC)} var maxSessionTime float64 - if err := rsponder.GetDerivedMaxSessionTime(cdr, &maxSessionTime); err == nil || err != utils.ErrAccountNotFound { + if err := rsponder.GetDerivedMaxSessionTime(cdr, &maxSessionTime); err == nil || + err != utils.ErrAccountNotFound { t.Error(err) } } diff --git a/utils/errors.go b/utils/errors.go index 54471678e..a2b813d21 100644 --- a/utils/errors.go +++ b/utils/errors.go @@ -46,6 +46,7 @@ var ( ErrResourceUnavailable = errors.New("RESOURCE_UNAVAILABLE") ErrNoActiveSession = errors.New("NO_ACTIVE_SESSION") ErrPartiallyExecuted = errors.New("PARTIALLY_EXECUTED") + ErrMaxUsageExceeded = errors.New("MAX_USAGE_EXCEEDED") ) // NewCGRError initialises a new CGRError From 642f5b8ab0c184767581693ce125c6d55bdea5b8 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 3 Nov 2017 13:13:08 +0200 Subject: [PATCH 09/75] Update CDRsFilter , --- apier/v1/apier_it_test.go | 4 +-- apier/v1/costs.go | 2 +- data/tariffplans/test/a1/Rates.csv | 1 + engine/cdr.go | 3 +- engine/storage_cdrs_it_test.go | 27 +--------------- engine/storage_mongo_stordb.go | 52 ++++++++++-------------------- engine/storage_sql.go | 34 ------------------- utils/apitpdata.go | 50 +++++++--------------------- 8 files changed, 34 insertions(+), 139 deletions(-) diff --git a/apier/v1/apier_it_test.go b/apier/v1/apier_it_test.go index c33445a81..136729664 100644 --- a/apier/v1/apier_it_test.go +++ b/apier/v1/apier_it_test.go @@ -1354,11 +1354,11 @@ func TestApierMaxDebitInexistentAcnt(t *testing.T) { func TestApierCdrServer(t *testing.T) { httpClient := new(http.Client) - cdrForm1 := url.Values{utils.ACCID: []string{"dsafdsaf"}, utils.CDRHOST: []string{"192.168.1.1"}, utils.REQTYPE: []string{utils.META_RATED}, utils.DIRECTION: []string{"*out"}, + cdrForm1 := url.Values{utils.ACCID: []string{"dsafdsaf"}, utils.CDRHOST: []string{"192.168.1.1"}, utils.REQTYPE: []string{utils.META_RATED}, utils.TENANT: []string{"cgrates.org"}, utils.CATEGORY: []string{"call"}, utils.ACCOUNT: []string{"1001"}, utils.SUBJECT: []string{"1001"}, utils.DESTINATION: []string{"1002"}, utils.SETUP_TIME: []string{"2013-11-07T08:42:22Z"}, utils.ANSWER_TIME: []string{"2013-11-07T08:42:26Z"}, utils.USAGE: []string{"10"}, "field_extr1": []string{"val_extr1"}, "fieldextr2": []string{"valextr2"}} - cdrForm2 := url.Values{utils.ACCID: []string{"adsafdsaf"}, utils.CDRHOST: []string{"192.168.1.1"}, utils.REQTYPE: []string{utils.META_RATED}, utils.DIRECTION: []string{"*out"}, + cdrForm2 := url.Values{utils.ACCID: []string{"adsafdsaf"}, utils.CDRHOST: []string{"192.168.1.1"}, utils.REQTYPE: []string{utils.META_RATED}, utils.TENANT: []string{"cgrates.org"}, utils.CATEGORY: []string{"call"}, utils.ACCOUNT: []string{"1001"}, utils.SUBJECT: []string{"1001"}, utils.DESTINATION: []string{"1002"}, utils.SETUP_TIME: []string{"2013-11-07T08:42:23Z"}, utils.ANSWER_TIME: []string{"2013-11-07T08:42:26Z"}, utils.USAGE: []string{"10"}, "field_extr1": []string{"val_extr1"}, "fieldextr2": []string{"valextr2"}} diff --git a/apier/v1/costs.go b/apier/v1/costs.go index b006e94e1..37e93c4c0 100644 --- a/apier/v1/costs.go +++ b/apier/v1/costs.go @@ -34,7 +34,7 @@ type AttrGetDataCost struct { } func (apier *ApierV1) GetDataCost(attrs AttrGetDataCost, reply *engine.DataCost) error { - usageAsDuration := time.Duration(attrs.Usage) * time.Second // Convert to seconds to match the loaded rates + usageAsDuration := time.Duration(attrs.Usage) * time.Nanosecond // Convert to seconds to match the loaded rates cd := &engine.CallDescriptor{ Direction: attrs.Direction, Category: attrs.Category, diff --git a/data/tariffplans/test/a1/Rates.csv b/data/tariffplans/test/a1/Rates.csv index aa04963f7..c4fbab57e 100644 --- a/data/tariffplans/test/a1/Rates.csv +++ b/data/tariffplans/test/a1/Rates.csv @@ -1 +1,2 @@ +#Id,ConnectFee,Rate,RateUnit,RateIncrement,GroupIntervalStart RT_DATA1,0,0.0,1048576,10240,0 diff --git a/engine/cdr.go b/engine/cdr.go index 243ae8046..ab987f5d3 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -803,7 +803,6 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr.SetupTime = cdrSql.SetupTime cdr.AnswerTime = cdrSql.AnswerTime cdr.Usage = time.Duration(cdrSql.Usage) - cdr.CostSource = cdrSql.CostSource cdr.Cost = cdrSql.Cost cdr.ExtraInfo = cdrSql.ExtraInfo @@ -813,7 +812,7 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { } } if cdrSql.CostDetails != "" { - if err = json.Unmarshal([]byte(cdrSql.CostDetails), cdr.CostDetails); err != nil { + if err = json.Unmarshal([]byte(cdrSql.CostDetails), &cdr.CostDetails); err != nil { return nil, err } } diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go index 912fdc408..46b1fe5ff 100644 --- a/engine/storage_cdrs_it_test.go +++ b/engine/storage_cdrs_it_test.go @@ -574,13 +574,6 @@ func testGetCDRs(cfg *config.CGRConfig) error { } else if len(CDRs) != 6 { return fmt.Errorf("testGetCDRs #35, unexpected number of CDRs returned: %+v", CDRs) } - - // Filter on direction - if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Directions: []string{utils.OUT}}, false); err != nil { - return fmt.Errorf("testGetCDRs #36 err: %v", err) - } else if len(CDRs) != 10 { - return fmt.Errorf("testGetCDRs #37, unexpected number of CDRs returned: %+v", CDRs) - } // Filter on Tenant if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Tenants: []string{"itsyscom.com"}}, false); err != nil { return fmt.Errorf("testGetCDRs #38 err: %v", err) @@ -661,7 +654,7 @@ func testGetCDRs(cfg *config.CGRConfig) error { return fmt.Errorf("testGetCDRs #63, unexpected number of CDRs returned: %+v", CDRs) } // Filter on MinUsage - if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinUsage: "125"}, false); err != nil { + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinUsage: "125s"}, false); err != nil { return fmt.Errorf("testGetCDRs #64, err: %v", err) } else if len(CDRs) != 2 { return fmt.Errorf("testGetCDRs #65, unexpected number of CDRs returned: %d", len(CDRs)) @@ -718,24 +711,6 @@ func testGetCDRs(cfg *config.CGRConfig) error { } else if len(CDRs) != 2 { return fmt.Errorf("testGetCDRs #77, unexpected number of CDRs returned: %+v", CDRs) } - // Filter on MinPDD - if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinPDD: "20ms"}, false); err != nil { - return fmt.Errorf("testGetCDRs #78, err: %v", err) - } else if len(CDRs) != 7 { - return fmt.Errorf("testGetCDRs #79, unexpected number of CDRs returned: %+v", CDRs) - } - // Filter on maxPdd - if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MaxPDD: "1s"}, false); err != nil { - return fmt.Errorf("testGetCDRs #80, err: %v", err) - } else if len(CDRs) != 8 { - return fmt.Errorf("testGetCDRs #81, unexpected number of CDRs returned: %+v", CDRs) - } - // Filter on minPdd, maxPdd - if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinPDD: "10ms", MaxPDD: "1s"}, false); err != nil { - return fmt.Errorf("testGetCDRs #82, err: %v", err) - } else if len(CDRs) != 6 { - return fmt.Errorf("testGetCDRs #83, unexpected number of CDRs returned: %+v", CDRs) - } // Combined filter if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{RequestTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}, false); err != nil { return fmt.Errorf("testGetCDRs #84, err: %v", err) diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 3169e154a..f21ede633 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -982,21 +982,7 @@ func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { // _, err := col(utils.CDRsTBL).UpdateAll(bson.M{CGRIDLow: bson.M{"$in": cgrIds}}, bson.M{"$set": bson.M{"deleted_at": time.Now()}}) 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.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { - return nil, 0, err - } else { - minPDD = &parsed - } - } - if len(qryFltr.MaxPDD) != 0 { - if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { - return nil, 0, err - } else { - maxPDD = &parsed - } - } + var minUsage, maxUsage *time.Duration if len(qryFltr.MinUsage) != 0 { if parsed, err := utils.ParseDurationWithNanosecs(qryFltr.MinUsage); err != nil { return nil, 0, err @@ -1012,26 +998,22 @@ func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } } filters := bson.M{ - CGRIDLow: bson.M{"$in": qryFltr.CGRIDs, "$nin": qryFltr.NotCGRIDs}, - RunIDLow: bson.M{"$in": qryFltr.RunIDs, "$nin": qryFltr.NotRunIDs}, - OrderIDLow: bson.M{"$gte": qryFltr.OrderIDStart, "$lt": qryFltr.OrderIDEnd}, - ToRLow: bson.M{"$in": qryFltr.ToRs, "$nin": qryFltr.NotToRs}, - CDRHostLow: bson.M{"$in": qryFltr.OriginHosts, "$nin": qryFltr.NotOriginHosts}, - CDRSourceLow: bson.M{"$in": qryFltr.Sources, "$nin": qryFltr.NotSources}, - RequestTypeLow: bson.M{"$in": qryFltr.RequestTypes, "$nin": qryFltr.NotRequestTypes}, - DirectionLow: bson.M{"$in": qryFltr.Directions, "$nin": qryFltr.NotDirections}, - TenantLow: bson.M{"$in": qryFltr.Tenants, "$nin": qryFltr.NotTenants}, - CategoryLow: bson.M{"$in": qryFltr.Categories, "$nin": qryFltr.NotCategories}, - AccountLow: bson.M{"$in": qryFltr.Accounts, "$nin": qryFltr.NotAccounts}, - SubjectLow: bson.M{"$in": qryFltr.Subjects, "$nin": qryFltr.NotSubjects}, - SupplierLow: bson.M{"$in": qryFltr.Suppliers, "$nin": qryFltr.NotSuppliers}, - DisconnectCauseLow: bson.M{"$in": qryFltr.DisconnectCauses, "$nin": qryFltr.NotDisconnectCauses}, - SetupTimeLow: bson.M{"$gte": qryFltr.SetupTimeStart, "$lt": qryFltr.SetupTimeEnd}, - AnswerTimeLow: bson.M{"$gte": qryFltr.AnswerTimeStart, "$lt": qryFltr.AnswerTimeEnd}, - CreatedAtLow: bson.M{"$gte": qryFltr.CreatedAtStart, "$lt": qryFltr.CreatedAtEnd}, - UpdatedAtLow: bson.M{"$gte": qryFltr.UpdatedAtStart, "$lt": qryFltr.UpdatedAtEnd}, - UsageLow: bson.M{"$gte": minUsage, "$lt": maxUsage}, - PDDLow: bson.M{"$gte": minPDD, "$lt": maxPDD}, + CGRIDLow: bson.M{"$in": qryFltr.CGRIDs, "$nin": qryFltr.NotCGRIDs}, + RunIDLow: bson.M{"$in": qryFltr.RunIDs, "$nin": qryFltr.NotRunIDs}, + OrderIDLow: bson.M{"$gte": qryFltr.OrderIDStart, "$lt": qryFltr.OrderIDEnd}, + ToRLow: bson.M{"$in": qryFltr.ToRs, "$nin": qryFltr.NotToRs}, + CDRHostLow: bson.M{"$in": qryFltr.OriginHosts, "$nin": qryFltr.NotOriginHosts}, + CDRSourceLow: bson.M{"$in": qryFltr.Sources, "$nin": qryFltr.NotSources}, + RequestTypeLow: bson.M{"$in": qryFltr.RequestTypes, "$nin": qryFltr.NotRequestTypes}, + TenantLow: bson.M{"$in": qryFltr.Tenants, "$nin": qryFltr.NotTenants}, + CategoryLow: bson.M{"$in": qryFltr.Categories, "$nin": qryFltr.NotCategories}, + AccountLow: bson.M{"$in": qryFltr.Accounts, "$nin": qryFltr.NotAccounts}, + SubjectLow: bson.M{"$in": qryFltr.Subjects, "$nin": qryFltr.NotSubjects}, + SetupTimeLow: bson.M{"$gte": qryFltr.SetupTimeStart, "$lt": qryFltr.SetupTimeEnd}, + AnswerTimeLow: bson.M{"$gte": qryFltr.AnswerTimeStart, "$lt": qryFltr.AnswerTimeEnd}, + CreatedAtLow: bson.M{"$gte": qryFltr.CreatedAtStart, "$lt": qryFltr.CreatedAtEnd}, + UpdatedAtLow: bson.M{"$gte": qryFltr.UpdatedAtStart, "$lt": qryFltr.UpdatedAtEnd}, + UsageLow: bson.M{"$gte": minUsage, "$lt": maxUsage}, //CostDetailsLow + "." + AccountLow: bson.M{"$in": qryFltr.RatedAccounts, "$nin": qryFltr.NotRatedAccounts}, //CostDetailsLow + "." + SubjectLow: bson.M{"$in": qryFltr.RatedSubjects, "$nin": qryFltr.NotRatedSubjects}, } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 13e1d4dd2..d1df9cedd 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -817,12 +817,6 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, if len(qryFltr.NotRequestTypes) != 0 { q = q.Where("request_type not in (?)", qryFltr.NotRequestTypes) } - if len(qryFltr.Directions) != 0 { - q = q.Where("direction in (?)", qryFltr.Directions) - } - if len(qryFltr.NotDirections) != 0 { - q = q.Where("direction not in (?)", qryFltr.NotDirections) - } if len(qryFltr.Tenants) != 0 { q = q.Where("tenant in (?)", qryFltr.Tenants) } @@ -869,18 +863,6 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, qIds.WriteString(" )") q = q.Where(qIds.String()) } - if len(qryFltr.Suppliers) != 0 { - q = q.Where("supplier in (?)", qryFltr.Subjects) - } - if len(qryFltr.NotSuppliers) != 0 { - q = q.Where("supplier not in (?)", qryFltr.NotSubjects) - } - if len(qryFltr.DisconnectCauses) != 0 { - q = q.Where("disconnect_cause in (?)", qryFltr.DisconnectCauses) - } - if len(qryFltr.NotDisconnectCauses) != 0 { - q = q.Where("disconnect_cause not in (?)", qryFltr.NotDisconnectCauses) - } if len(qryFltr.Costs) != 0 { q = q.Where(utils.CDRsTBL+".cost in (?)", qryFltr.Costs) } @@ -974,22 +956,6 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } } - if len(qryFltr.MinPDD) != 0 { - if minPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { - return nil, 0, err - } else { - q = q.Where("pdd >= ?", minPDD.Nanoseconds()) - } - - } - if len(qryFltr.MaxPDD) != 0 { - if maxPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { - return nil, 0, err - } else { - q = q.Where("pdd < ?", maxPDD.Nanoseconds()) - } - } - if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { q = q.Where("cost >= ?", *qryFltr.MinCost) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 402201db9..c3cc74cf2 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -761,7 +761,6 @@ func (self *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) OriginHosts: self.CdrHosts, Sources: self.CdrSources, RequestTypes: self.ReqTypes, - Directions: self.Directions, Tenants: self.Tenants, Categories: self.Categories, Accounts: self.Accounts, @@ -835,7 +834,6 @@ func (self *AttrGetCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) { OriginHosts: self.CdrHosts, Sources: self.CdrSources, RequestTypes: self.ReqTypes, - Directions: self.Directions, Tenants: self.Tenants, Categories: self.Categories, Accounts: self.Accounts, @@ -879,7 +877,6 @@ type AttrRateCdrs struct { CdrHosts []string // If provided, it will filter cdrhost CdrSources []string // If provided, it will filter cdrsource ReqTypes []string // If provided, it will fiter reqtype - Directions []string // If provided, it will fiter direction Tenants []string // If provided, it will filter tenant Categories []string // If provided, it will filter çategory Accounts []string // If provided, it will filter account @@ -902,7 +899,6 @@ func (attrRateCDRs *AttrRateCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, er Sources: attrRateCDRs.CdrSources, ToRs: attrRateCDRs.TORs, RequestTypes: attrRateCDRs.ReqTypes, - Directions: attrRateCDRs.Directions, Tenants: attrRateCDRs.Tenants, Categories: attrRateCDRs.Categories, Accounts: attrRateCDRs.Accounts, @@ -1013,8 +1009,6 @@ type CDRsFilter struct { NotToRs []string // Filter specific TORs out RequestTypes []string // If provided, it will fiter reqtype NotRequestTypes []string // Filter out specific request types - Directions []string // If provided, it will fiter direction - NotDirections []string // Filter out specific directions Tenants []string // If provided, it will filter tenant NotTenants []string // If provided, it will filter tenant Categories []string // If provided, it will filter çategory @@ -1025,10 +1019,6 @@ type CDRsFilter struct { NotSubjects []string // Filter out specific subjects DestinationPrefixes []string // If provided, it will filter on destination prefix NotDestinationPrefixes []string // Filter out specific destination prefixes - Suppliers []string // If provided, it will filter the supplier - NotSuppliers []string // Filter out specific suppliers - DisconnectCauses []string // Filter for disconnect Cause - NotDisconnectCauses []string // Filter out specific disconnect causes Costs []float64 // Query based on costs specified NotCosts []float64 // Filter out specific costs out from result ExtraFields map[string]string // Query based on extra fields content @@ -1045,8 +1035,6 @@ type CDRsFilter struct { UpdatedAtEnd *time.Time // End interval, smaller than MinUsage string // Start of the usage interval (>=) MaxUsage string // End of the usage interval (<) - MinPDD string // Start of the pdd interval (>=) - MaxPDD string // End of the pdd interval (<) MinCost *float64 // Start of the cost interval (>=) MaxCost *float64 // End of the usage interval (<) Unscoped bool // Include soft-deleted records in results @@ -1069,8 +1057,6 @@ type RPCCDRsFilter struct { NotToRs []string // Filter specific TORs out RequestTypes []string // If provided, it will fiter reqtype NotRequestTypes []string // Filter out specific request types - Directions []string // If provided, it will fiter direction - NotDirections []string // Filter out specific directions Tenants []string // If provided, it will filter tenant NotTenants []string // If provided, it will filter tenant Categories []string // If provided, it will filter çategory @@ -1081,10 +1067,6 @@ type RPCCDRsFilter struct { NotSubjects []string // Filter out specific subjects DestinationPrefixes []string // If provided, it will filter on destination prefix NotDestinationPrefixes []string // Filter out specific destination prefixes - Suppliers []string // If provided, it will filter the supplier - NotSuppliers []string // Filter out specific suppliers - DisconnectCauses []string // Filter for disconnect Cause - NotDisconnectCauses []string // Filter out specific disconnect causes Costs []float64 // Query based on costs specified NotCosts []float64 // Filter out specific costs out from result ExtraFields map[string]string // Query based on extra fields content @@ -1101,8 +1083,6 @@ type RPCCDRsFilter struct { UpdatedAtEnd string // End interval, smaller than MinUsage string // Start of the usage interval (>=) MaxUsage string // End of the usage interval (<) - MinPDD string // Start of the pdd interval (>=) - MaxPDD string // End of the pdd interval (<) MinCost *float64 // Start of the cost interval (>=) MaxCost *float64 // End of the usage interval (<) Paginator // Add pagination @@ -1122,8 +1102,6 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) { NotSources: self.NotSources, RequestTypes: self.RequestTypes, NotRequestTypes: self.NotRequestTypes, - Directions: self.Directions, - NotDirections: self.NotDirections, Tenants: self.Tenants, NotTenants: self.NotTenants, Categories: self.Categories, @@ -1134,23 +1112,17 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) { NotSubjects: self.NotSubjects, DestinationPrefixes: self.DestinationPrefixes, NotDestinationPrefixes: self.NotDestinationPrefixes, - Suppliers: self.Suppliers, - NotSuppliers: self.NotSuppliers, - DisconnectCauses: self.DisconnectCauses, - NotDisconnectCauses: self.NotDisconnectCauses, - Costs: self.Costs, - NotCosts: self.NotCosts, - ExtraFields: self.ExtraFields, - NotExtraFields: self.NotExtraFields, - OrderIDStart: self.OrderIDStart, - OrderIDEnd: self.OrderIDEnd, - MinUsage: self.MinUsage, - MaxUsage: self.MaxUsage, - MinPDD: self.MinPDD, - MaxPDD: self.MaxPDD, - MinCost: self.MinCost, - MaxCost: self.MaxCost, - Paginator: self.Paginator, + Costs: self.Costs, + NotCosts: self.NotCosts, + ExtraFields: self.ExtraFields, + NotExtraFields: self.NotExtraFields, + OrderIDStart: self.OrderIDStart, + OrderIDEnd: self.OrderIDEnd, + MinUsage: self.MinUsage, + MaxUsage: self.MaxUsage, + MinCost: self.MinCost, + MaxCost: self.MaxCost, + Paginator: self.Paginator, } if len(self.SetupTimeStart) != 0 { if sTimeStart, err := ParseTimeDetectLayout(self.SetupTimeStart, timezone); err != nil { From fda5210a4916141f606981f82c2e76e9dbce30ca Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 3 Nov 2017 13:38:40 +0200 Subject: [PATCH 10/75] Update CDRsFilter , RPCCDRsFilter , AttrExpFileCdrs structure --- utils/apitpdata.go | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index c3cc74cf2..a53f77b9a 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -736,7 +736,6 @@ type AttrExpFileCdrs struct { CdrHosts []string // If provided, it will filter cdrhost CdrSources []string // If provided, it will filter cdrsource ReqTypes []string // If provided, it will fiter reqtype - Directions []string // If provided, it will fiter direction Tenants []string // If provided, it will filter tenant Categories []string // If provided, it will filter çategory Accounts []string // If provided, it will filter account From 095bb4c56cce8013911e9c8eb861a92b524db570 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Nov 2017 13:21:01 +0100 Subject: [PATCH 11/75] CacheS in engine, config cache exporting update --- agents/libdmt.go | 3 ++- agents/libdmt_test.go | 8 ++++-- cache/cache.go | 2 +- cmd/cgr-engine/cgr-engine.go | 14 +++++----- cmd/cgr-engine/rater.go | 45 ++++++++++++++++---------------- cmd/cgr-loader/cgr-loader.go | 3 ++- cmd/cgr-migrator/cgr-migrator.go | 9 ++++--- cmd/cgr-tester/cgr-tester.go | 3 ++- config/config.go | 10 ++++--- config/config_test.go | 5 ++-- engine/caches.go | 44 +++++++++++++++++++++++++++++++ engine/datamanager.go | 2 +- engine/libtest.go | 3 ++- engine/storage_map.go | 2 +- general_tests/auth_test.go | 2 +- general_tests/smschrg1_test.go | 2 +- 16 files changed, 109 insertions(+), 48 deletions(-) create mode 100644 engine/caches.go diff --git a/agents/libdmt.go b/agents/libdmt.go index e4b518ecc..c3bc67aea 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -270,7 +270,8 @@ func splitIntoInterface(content, sep string) []interface{} { // avpsWithPath is used to find AVPs by specifying RSRField as filter func avpsWithPath(m *diam.Message, rsrFld *utils.RSRField) ([]*diam.AVP, error) { - return m.FindAVPsWithPath(splitIntoInterface(rsrFld.Id, utils.HIERARCHY_SEP), dict.UndefinedVendorID) + return m.FindAVPsWithPath( + splitIntoInterface(rsrFld.Id, utils.HIERARCHY_SEP), dict.UndefinedVendorID) } func passesFieldFilter(m *diam.Message, fieldFilter *utils.RSRField, processorVars map[string]string) (bool, int) { diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index eadd80e7c..2a747babb 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -108,12 +108,16 @@ func TestMetaValueExponent(t *testing.T) { }), }, }) - if val, err := metaValueExponent(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 10); err != nil { + if val, err := metaValueExponent(m, utils.ParseRSRFieldsMustCompile( + "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", + utils.INFIELD_SEP), 10); err != nil { t.Error(err) } else if val != "0.1" { t.Error("Received: ", val) } - if _, err = metaValueExponent(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 10); err == nil { + if _, err = metaValueExponent(m, utils.ParseRSRFieldsMustCompile( + "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", + utils.INFIELD_SEP), 10); err == nil { t.Error("Should have received error") // Insufficient number arguments } } diff --git a/cache/cache.go b/cache/cache.go index 521fc80ee..9fb0a5de7 100755 --- a/cache/cache.go +++ b/cache/cache.go @@ -56,7 +56,7 @@ type transactionItem struct { func init() { // ToDo: revert to nil config as soon as we handle cacheInstances properly dfCfg, _ := config.NewDefaultCGRConfig() - NewCache(dfCfg.CacheConfig) + NewCache(dfCfg.CacheCfg()) } func NewCache(cacheCfg config.CacheConfig) { diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 9e714a964..49a5cc983 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -741,7 +741,8 @@ func main() { log.Fatalf("Could not parse config: ", err) return } - config.SetCgrConfig(cfg) // Share the config object + config.SetCgrConfig(cfg) // Share the config object + cache.NewCache(cfg.CacheCfg()) // init cache // init syslog if err = initLogger(cfg); err != nil { log.Fatalf("Could not initialize syslog connection, err: <%s>", err.Error()) @@ -753,16 +754,14 @@ func main() { } utils.Logger.SetLogLevel(lgLevel) - // Init cache - cache.NewCache(cfg.CacheConfig) - var loadDb engine.LoadStorage var cdrDb engine.CdrStorage var dm *engine.DataManager - if cfg.RALsEnabled || cfg.CDRStatsEnabled || cfg.PubSubServerEnabled || cfg.AliasesServerEnabled || cfg.UserServerEnabled || cfg.SchedulerEnabled { + if cfg.RALsEnabled || cfg.CDRStatsEnabled || cfg.PubSubServerEnabled || + cfg.AliasesServerEnabled || cfg.UserServerEnabled || cfg.SchedulerEnabled { dm, err = engine.ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, - cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheConfig, cfg.LoadHistorySize) + cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) if err != nil { // Cannot configure getter database, show stopper utils.Logger.Crit(fmt.Sprintf("Could not configure dataDb: %s exiting!", err)) return @@ -776,7 +775,8 @@ func main() { } if cfg.RALsEnabled || cfg.CDRSEnabled || cfg.SchedulerEnabled { // Only connect to storDb if necessary storDb, err := engine.ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, - cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns, cfg.StorDBConnMaxLifetime, cfg.StorDBCDRSIndexes) + cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, cfg.StorDBMaxOpenConns, + cfg.StorDBMaxIdleConns, cfg.StorDBConnMaxLifetime, cfg.StorDBCDRSIndexes) if err != nil { // Cannot configure logger database, show stopper utils.Logger.Crit(fmt.Sprintf("Could not configure logger database: %s exiting!", err)) return diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index 4090ff227..2c1abeafe 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -37,71 +37,72 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC serviceManager *servmanager.ServiceManager, server *utils.Server, dm *engine.DataManager, loadDb engine.LoadStorage, cdrDb engine.CdrStorage, stopHandled *bool, exitChan chan bool) { var waitTasks []chan struct{} - + cacheCfg := cfg.CacheCfg() //Cache load cacheTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) - var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string - if cCfg, has := cfg.CacheConfig[utils.CacheDestinations]; !has || !cCfg.Precache { + var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, + lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string + if cCfg, has := cacheCfg[utils.CacheDestinations]; !has || !cCfg.Precache { dstIDs = make([]string, 0) // Don't cache any } - if cCfg, has := cfg.CacheConfig[utils.CacheReverseDestinations]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheReverseDestinations]; !has || !cCfg.Precache { rvDstIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheRatingPlans]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheRatingPlans]; !has || !cCfg.Precache { rplIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheRatingProfiles]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheRatingProfiles]; !has || !cCfg.Precache { rpfIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheActions]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheActions]; !has || !cCfg.Precache { actIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheActionPlans]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheActionPlans]; !has || !cCfg.Precache { aplIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheAccountActionPlans]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheAccountActionPlans]; !has || !cCfg.Precache { aapIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheActionTriggers]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheActionTriggers]; !has || !cCfg.Precache { atrgIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheSharedGroups]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheSharedGroups]; !has || !cCfg.Precache { sgIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheLCRRules]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheLCRRules]; !has || !cCfg.Precache { lcrIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheDerivedChargers]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheDerivedChargers]; !has || !cCfg.Precache { dcIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheAliases]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheAliases]; !has || !cCfg.Precache { alsIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheReverseAliases]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheReverseAliases]; !has || !cCfg.Precache { rvAlsIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheResourceProfiles]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheResourceProfiles]; !has || !cCfg.Precache { rspIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheResources]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheResources]; !has || !cCfg.Precache { resIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheStatQueues]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheStatQueues]; !has || !cCfg.Precache { stqIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheStatQueueProfiles]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheStatQueueProfiles]; !has || !cCfg.Precache { stqpIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheThresholds]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheThresholds]; !has || !cCfg.Precache { thIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheThresholdProfiles]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheThresholdProfiles]; !has || !cCfg.Precache { thpIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheFilters]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheFilters]; !has || !cCfg.Precache { fltrIDs = make([]string, 0) } diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 920012514..f4197cba8 100755 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -81,7 +81,8 @@ func main() { var rater, cdrstats, users rpcclient.RpcClientConnection var loader engine.LoadReader - dm, errDataDB = engine.ConfigureDataStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding, config.CgrConfig().CacheConfig, *loadHistorySize) + dm, errDataDB = engine.ConfigureDataStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, + *datadb_user, *datadb_pass, *dbdata_encoding, config.CgrConfig().CacheCfg(), *loadHistorySize) if *fromStorDb || *toStorDb { storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding, config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index b5ebb06a1..ba7b1ef45 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -89,9 +89,12 @@ func main() { log.Print("Initializing storDB:", *storDBType) } var dm *engine.DataManager - dm, _ = engine.ConfigureDataStorage(*dataDBType, *dataDBHost, *dataDBPort, *dataDBName, *dataDBUser, *dataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) - storDB, err := engine.ConfigureStorStorage(*storDBType, *storDBHost, *storDBPort, *storDBName, *storDBUser, *storDBPass, *dbDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + dm, _ = engine.ConfigureDataStorage(*dataDBType, *dataDBHost, *dataDBPort, *dataDBName, + *dataDBUser, *dataDBPass, *dbDataEncoding, config.CgrConfig().CacheCfg(), *loadHistorySize) + storDB, err := engine.ConfigureStorStorage(*storDBType, *storDBHost, *storDBPort, + *storDBName, *storDBUser, *storDBPass, *dbDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, + config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } diff --git a/cmd/cgr-tester/cgr-tester.go b/cmd/cgr-tester/cgr-tester.go index 1e39f12ed..7ba39f943 100644 --- a/cmd/cgr-tester/cgr-tester.go +++ b/cmd/cgr-tester/cgr-tester.go @@ -61,7 +61,8 @@ var ( ) func durInternalRater(cd *engine.CallDescriptor) (time.Duration, error) { - dm, err := engine.ConfigureDataStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding, cgrConfig.CacheConfig, *loadHistorySize) + dm, err := engine.ConfigureDataStorage(*datadb_type, *datadb_host, *datadb_port, + *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding, cgrConfig.CacheCfg(), *loadHistorySize) if err != nil { return nilDuration, fmt.Errorf("Could not connect to data database: %s", err.Error()) } diff --git a/config/config.go b/config/config.go index 2d025ef6d..67469ece0 100755 --- a/config/config.go +++ b/config/config.go @@ -69,7 +69,7 @@ func NewDefaultCGRConfig() (*CGRConfig, error) { cfg.InstanceID = utils.GenUUID() cfg.DataFolderPath = "/usr/share/cgrates/" cfg.SmGenericConfig = new(SmGenericConfig) - cfg.CacheConfig = make(CacheConfig) + cfg.cacheConfig = make(CacheConfig) cfg.SmFsConfig = new(SmFsConfig) cfg.SmKamConfig = new(SmKamConfig) cfg.SmOsipsConfig = new(SmOsipsConfig) @@ -202,7 +202,7 @@ type CGRConfig struct { StorDBConnMaxLifetime int StorDBCDRSIndexes []string DBDataEncoding string // The encoding used to store object data in strings: - CacheConfig CacheConfig + cacheConfig CacheConfig RPCJSONListen string // RPC JSON listening address RPCGOBListen string // RPC GOB listening address HTTPListen string // HTTP listening address @@ -822,7 +822,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { } if jsnCacheCfg != nil { - if err := self.CacheConfig.loadFromJsonCfg(jsnCacheCfg); err != nil { + if err := self.cacheConfig.loadFromJsonCfg(jsnCacheCfg); err != nil { return err } } @@ -1247,3 +1247,7 @@ func (self *CGRConfig) SMAsteriskCfg() *SMAsteriskCfg { func (cfg *CGRConfig) FilterSCfg() *FilterSCfg { return cfg.filterSCfg } + +func (cfg *CGRConfig) CacheCfg() CacheConfig { + return cfg.cacheConfig +} diff --git a/config/config_test.go b/config/config_test.go index 45beaa529..6f6264d26 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -509,8 +509,9 @@ func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) { TTL: time.Duration(0), StaticTTL: false, Precache: false}, utils.CacheFilters: &CacheParamConfig{Limit: -1, TTL: time.Duration(0), StaticTTL: false, Precache: false}} - if !reflect.DeepEqual(eCacheCfg, cgrCfg.CacheConfig) { - t.Errorf("received: %s, \nexpecting: %s", utils.ToJSON(eCacheCfg), utils.ToJSON(cgrCfg.CacheConfig)) + if !reflect.DeepEqual(eCacheCfg, cgrCfg.CacheCfg()) { + t.Errorf("received: %s, \nexpecting: %s", + utils.ToJSON(eCacheCfg), utils.ToJSON(cgrCfg.CacheCfg())) } } diff --git a/engine/caches.go b/engine/caches.go new file mode 100644 index 000000000..8dbadbf8b --- /dev/null +++ b/engine/caches.go @@ -0,0 +1,44 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package engine + +import ( + "sync" + + "github.com/cgrates/cgrates/cache" + "github.com/cgrates/cgrates/config" +) + +func NewCacheS(cfg *config.CGRConfig, dm *DataManager) (c *CacheS) { + c = &CacheS{cfg: cfg, dm: dm, + cItems: make(map[string]chan struct{})} + for k := range cfg.CacheCfg() { + c.cItems[k] = make(chan struct{}) + } + cache.NewCache(cfg.CacheCfg()) // init cache + return +} + +// CacheS deals with cache preload and other cache related tasks +type CacheS struct { + cfg *config.CGRConfig + dm *DataManager + cItems map[string]chan struct{} // signal receiving of the + lMux sync.RWMutex +} diff --git a/engine/datamanager.go b/engine/datamanager.go index 3e771b101..22b1241da 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -23,7 +23,7 @@ import ( ) func NewDataManager(dataDB DataDB) *DataManager { - return &DataManager{dataDB: dataDB, cacheCfg: config.CgrConfig().CacheConfig} + return &DataManager{dataDB: dataDB, cacheCfg: config.CgrConfig().CacheCfg()} } // DataManager is the data storage manager for CGRateS diff --git a/engine/libtest.go b/engine/libtest.go index 66df14ab5..c121da537 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -34,7 +34,8 @@ import ( ) func InitDataDb(cfg *config.CGRConfig) error { - dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheConfig, cfg.LoadHistorySize) + dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, + cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) if err != nil { return err } diff --git a/engine/storage_map.go b/engine/storage_map.go index b0201a95a..4eaaaff6c 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -72,7 +72,7 @@ func (s storage) smembers(key string, ms Marshaler) (idMap utils.StringMap, ok b func NewMapStorage() (*MapStorage, error) { return &MapStorage{dict: make(map[string][]byte), ms: NewCodecMsgpackMarshaler(), - cacheCfg: config.CgrConfig().CacheConfig}, nil + cacheCfg: config.CgrConfig().CacheCfg()}, nil } func NewMapStorageJson() (mpStorage *MapStorage, err error) { diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index 2924a89b7..f856b61f4 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -31,7 +31,7 @@ var dbAuth *engine.DataManager var rsponder *engine.Responder func TestAuthSetStorage(t *testing.T) { - config.CgrConfig().CacheConfig[utils.CacheRatingPlans].Precache = true // precache rating plan + config.CgrConfig().CacheCfg()[utils.CacheRatingPlans].Precache = true // precache rating plan data, _ := engine.NewMapStorageJson() dbAuth = engine.NewDataManager(data) engine.SetDataStorage(dbAuth) diff --git a/general_tests/smschrg1_test.go b/general_tests/smschrg1_test.go index c0582cfd5..cadc357f5 100644 --- a/general_tests/smschrg1_test.go +++ b/general_tests/smschrg1_test.go @@ -28,7 +28,7 @@ import ( ) func TestSMSSetStorageSmsChrg1(t *testing.T) { - config.CgrConfig().CacheConfig[utils.CacheRatingPlans].Precache = true // precache rating plan + config.CgrConfig().CacheCfg()[utils.CacheRatingPlans].Precache = true // precache rating plan data, _ := engine.NewMapStorageJson() dataDB = engine.NewDataManager(data) engine.SetDataStorage(dataDB) From 47f7fb3ec0da0bcb07231a4a12d538b58bb3aa00 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Nov 2017 13:48:00 +0100 Subject: [PATCH 12/75] Engine tests fixes --- engine/datamanager_it_test.go | 5 +++-- engine/onstor_it_test.go | 8 +++++--- engine/version.go | 5 +++-- engine/versions_it_test.go | 38 +++++++++++++++++++++++------------ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/engine/datamanager_it_test.go b/engine/datamanager_it_test.go index 22d286ce8..07c06e19b 100644 --- a/engine/datamanager_it_test.go +++ b/engine/datamanager_it_test.go @@ -58,8 +58,9 @@ func TestDMitMongo(t *testing.T) { if err != nil { t.Fatal(err) } - dataDB, err := NewMongoStorage(mgoITCfg.StorDBHost, mgoITCfg.StorDBPort, mgoITCfg.StorDBName, mgoITCfg.StorDBUser, mgoITCfg.StorDBPass, - utils.StorDB, nil, mgoITCfg.CacheConfig, mgoITCfg.LoadHistorySize) + dataDB, err := NewMongoStorage(mgoITCfg.StorDBHost, mgoITCfg.StorDBPort, + mgoITCfg.StorDBName, mgoITCfg.StorDBUser, mgoITCfg.StorDBPass, + utils.StorDB, nil, mgoITCfg.CacheCfg(), mgoITCfg.LoadHistorySize) if err != nil { t.Fatal("Could not connect to Redis", err.Error()) } diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index a296737a3..f6da2dc44 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -99,7 +99,8 @@ var sTestsOnStorIT = []func(t *testing.T){ func TestOnStorITRedisConnect(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() - rdsITdb, err = NewRedisStorage(fmt.Sprintf("%s:%s", cfg.DataDbHost, cfg.DataDbPort), 4, cfg.DataDbPass, cfg.DBDataEncoding, utils.REDIS_MAX_CONNS, nil, 1) + rdsITdb, err = NewRedisStorage(fmt.Sprintf("%s:%s", cfg.DataDbHost, cfg.DataDbPort), 4, + cfg.DataDbPass, cfg.DBDataEncoding, utils.REDIS_MAX_CONNS, nil, 1) if err != nil { t.Fatal("Could not connect to Redis", err.Error()) } @@ -119,8 +120,9 @@ func TestOnStorITMongoConnect(t *testing.T) { if err != nil { t.Fatal(err) } - if mgoITdb, err = NewMongoStorage(mgoITCfg.StorDBHost, mgoITCfg.StorDBPort, mgoITCfg.StorDBName, mgoITCfg.StorDBUser, mgoITCfg.StorDBPass, - utils.StorDB, nil, mgoITCfg.CacheConfig, mgoITCfg.LoadHistorySize); err != nil { + if mgoITdb, err = NewMongoStorage(mgoITCfg.StorDBHost, mgoITCfg.StorDBPort, + mgoITCfg.StorDBName, mgoITCfg.StorDBUser, mgoITCfg.StorDBPass, + utils.StorDB, nil, mgoITCfg.CacheCfg(), mgoITCfg.LoadHistorySize); err != nil { t.Fatal(err) } onStorCfg = mgoITCfg.StorDBName diff --git a/engine/version.go b/engine/version.go index 9abfde5c8..f364f8c3f 100644 --- a/engine/version.go +++ b/engine/version.go @@ -105,11 +105,12 @@ func (vers Versions) Compare(curent Versions, storType string) string { } func CurrentStorDBVersions() Versions { - return Versions{utils.COST_DETAILS: 2, utils.CDRsTBL: 2} + return Versions{utils.COST_DETAILS: 2, utils.CDRs: 2} } func CurrentDataDBVersions() Versions { - return Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + return Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, + utils.ActionPlans: 2, utils.SharedGroups: 2} } func CurrentDBVersions(storType string) Versions { diff --git a/engine/versions_it_test.go b/engine/versions_it_test.go index c528d82f2..9b38aff9f 100644 --- a/engine/versions_it_test.go +++ b/engine/versions_it_test.go @@ -46,12 +46,15 @@ func TestVersionsITMongo(t *testing.T) { if cfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "tutmongo")); err != nil { t.Fatal(err) } - if dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, - cfg.DBDataEncoding, cfg.CacheConfig, *loadHistorySize); err != nil { + if dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, + cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, + cfg.DBDataEncoding, cfg.CacheCfg(), *loadHistorySize); err != nil { log.Fatal(err) } - storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, + cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, + config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } @@ -66,13 +69,16 @@ func TestVersionsITRedisMYSQL(t *testing.T) { if cfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "tutmysql")); err != nil { t.Fatal(err) } - dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheConfig, *loadHistorySize) + dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, + cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), *loadHistorySize) if err != nil { log.Fatal(err) } - storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, + cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, + config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } @@ -87,12 +93,15 @@ func TestVersionsITRedisPostgres(t *testing.T) { if cfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "postgres")); err != nil { t.Fatal(err) } - dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheConfig, *loadHistorySize) + dm3, err = ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, + cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), *loadHistorySize) if err != nil { log.Fatal(err) } - storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + storageDb, err = ConfigureStorStorage(cfg.StorDBType, cfg.StorDBHost, + cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, + config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } @@ -120,7 +129,8 @@ func testVersion(t *testing.T) { storType := dm3.DataDB().GetStorageType() switch storType { case utils.MONGO, utils.MAPSTOR: - currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2} + currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, + utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2} test = "Migration needed: please backup cgr data and run : " case utils.REDIS: @@ -159,8 +169,10 @@ func testVersion(t *testing.T) { storType = storageDb.GetStorageType() switch storType { case utils.MONGO, utils.MAPSTOR: - currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2} - testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2} + currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, + utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} + testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, + utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} test = "Migration needed: please backup cgr data and run : " case utils.POSTGRES, utils.MYSQL: currentVersion = CurrentStorDBVersions() From 4d3504b2139be246bab4b3bebeed54168d867509 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 3 Nov 2017 16:13:04 +0200 Subject: [PATCH 13/75] Populare OrderID in CdrSql --- engine/cdr.go | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/cdr.go b/engine/cdr.go index ab987f5d3..3d072fe80 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -793,6 +793,7 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source cdr.OriginID = cdrSql.OriginID + cdr.OrderID = cdrSql.ID cdr.ToR = cdrSql.TOR cdr.RequestType = cdrSql.RequestType cdr.Tenant = cdrSql.Tenant From 774dc123c8d8d9b89d2fdfd91305524200dd9c74 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Nov 2017 16:48:28 +0100 Subject: [PATCH 14/75] ExternalCDR with time string as Usage for *voice ToR, diameter test fixes --- agents/dmtagent.go | 3 +- agents/dmtagent_it_test.go | 105 +++++++++++++++--------- agents/libdmt.go | 20 ++--- agents/libdmt_test.go | 14 ++-- agents/radagent_it_test.go | 2 +- data/conf/samples/dmtagent/cgrates.json | 4 + engine/cdr.go | 9 +- 7 files changed, 95 insertions(+), 62 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index cdf75b279..f5be11dcb 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -75,7 +75,8 @@ func (self *DiameterAgent) handlers() diam.Handler { return dSM } -func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProcessor, processorVars map[string]string, cca *CCA) (bool, error) { +func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProcessor, + processorVars map[string]string, cca *CCA) (bool, error) { passesAllFilters := true for _, fldFilter := range reqProcessor.RequestFilter { if passes, _ := passesFieldFilter(ccr.diamMessage, fldFilter, nil); !passes { diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index a38257282..121899d84 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -64,27 +64,6 @@ func TestDmtAgentInitCfg(t *testing.T) { rplyTimeout, _ = utils.ParseDurationWithSecs(*replyTimeout) } -// Remove data in both rating and accounting db -func TestDmtAgentResetDataDb(t *testing.T) { - if err := engine.InitDataDb(daCfg); err != nil { - t.Fatal(err) - } -} - -// Wipe out the cdr database -func TestDmtAgentResetStorDb(t *testing.T) { - if err := engine.InitStorDb(daCfg); err != nil { - t.Fatal(err) - } -} - -// Start CGR Engine -func TestDmtAgentStartEngine(t *testing.T) { - if _, err := engine.StopStartEngine(daCfgPath, 4000); err != nil { - t.Fatal(err) - } -} - func TestDmtAgentCCRAsSMGenericEvent(t *testing.T) { cfgDefaults, _ := config.NewDefaultCGRConfig() loadDictionaries(cfgDefaults.DiameterAgentCfg().DictionariesDir, "UNIT_TEST") @@ -133,10 +112,15 @@ func TestDmtAgentCCRAsSMGenericEvent(t *testing.T) { if ccr.diamMessage, err = ccr.AsDiameterMessage(); err != nil { t.Error(err) } - eSMGE := sessionmanager.SMGenericEvent{"EventName": DIAMETER_CCR, "OriginID": "routinga;1442095190;1476802709", - "Account": "*users", "AnswerTime": "2015-11-23 12:22:24 +0000 UTC", "Category": "call", - "Destination": "4986517174964", "Direction": "*out", "RequestType": "*users", "SetupTime": "2015-11-23 12:22:24 +0000 UTC", - "Subject": "*users", "SubscriberId": "4986517174963", "ToR": "*voice", "Tenant": "*users", "Usage": "300"} + eSMGE := sessionmanager.SMGenericEvent{"EventName": DIAMETER_CCR, + "OriginID": "routinga;1442095190;1476802709", + "Account": "*users", "Category": "call", + "AnswerTime": "2015-11-23 12:22:24 +0000 UTC", + "Destination": "4986517174964", "Direction": "*out", + "RequestType": "*users", + "SetupTime": "2015-11-23 12:22:24 +0000 UTC", + "Subject": "*users", "SubscriberId": "4986517174963", + "ToR": "*voice", "Tenant": "*users", "Usage": "5m0s"} ccrFields := []*config.CfgCdrField{ &config.CfgCdrField{Tag: "TOR", FieldId: "ToR", Type: "*composed", Value: utils.ParseRSRFieldsMustCompile("^*voice", utils.INFIELD_SEP), Mandatory: true}, @@ -172,25 +156,35 @@ func TestDmtAgentCCRAsSMGenericEvent(t *testing.T) { func TestDmtAgentPopulateCCTotalOctets(t *testing.T) { daRP := &config.DARequestProcessor{CCAFields: []*config.CfgCdrField{ - &config.CfgCdrField{Tag: "GrantedUnit", FieldFilter: utils.ParseRSRFieldsMustCompile("CGRError(^$)", utils.INFIELD_SEP), - FieldId: "Multiple-Services-Credit-Control>Granted-Service-Unit>CC-Time", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("CGRMaxUsage", utils.INFIELD_SEP), Mandatory: true}, - &config.CfgCdrField{Tag: "GrantedOctet", FieldFilter: utils.ParseRSRFieldsMustCompile("CGRError(^$)", utils.INFIELD_SEP), - FieldId: "Multiple-Services-Credit-Control>Granted-Service-Unit>CC-Total-Octets", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("CGRMaxUsage", utils.INFIELD_SEP), Mandatory: true}, + &config.CfgCdrField{Tag: "GrantedUnit", + FieldFilter: utils.ParseRSRFieldsMustCompile("CGRError(^$)", utils.INFIELD_SEP), + FieldId: "Multiple-Services-Credit-Control>Granted-Service-Unit>CC-Time", + Type: utils.META_COMPOSED, + Value: utils.ParseRSRFieldsMustCompile("CGRMaxUsage", utils.INFIELD_SEP), Mandatory: true}, + &config.CfgCdrField{Tag: "GrantedOctet", + FieldFilter: utils.ParseRSRFieldsMustCompile("CGRError(^$)", utils.INFIELD_SEP), + FieldId: "Multiple-Services-Credit-Control>Granted-Service-Unit>CC-Total-Octets", + Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("CGRMaxUsage", utils.INFIELD_SEP), + Mandatory: true}, }} ccr := new(CCR) ccr.diamMessage = ccr.AsBareDiameterMessage() cca := NewBareCCAFromCCR(ccr, "cgr-da", "cgrates.org") - if err := cca.SetProcessorAVPs(daRP, map[string]string{CGRError: "", CGRMaxUsage: "153600"}); err != nil { + if err := cca.SetProcessorAVPs(daRP, + map[string]string{CGRError: "", CGRMaxUsage: "153600"}); err != nil { t.Error(err) } - if avps, err := cca.diamMessage.FindAVPsWithPath([]interface{}{"Multiple-Services-Credit-Control", "Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil { + if avps, err := cca.diamMessage.FindAVPsWithPath([]interface{}{ + "Multiple-Services-Credit-Control", "Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Not found") } else if strResult := avpValAsString(avps[0]); strResult != "153600" { // Result-Code set in the template t.Errorf("Expecting 153600, received: %s", strResult) } - if avps, err := cca.diamMessage.FindAVPsWithPath([]interface{}{"Multiple-Services-Credit-Control", "Granted-Service-Unit", "CC-Total-Octets"}, dict.UndefinedVendorID); err != nil { + if avps, err := cca.diamMessage.FindAVPsWithPath([]interface{}{ + "Multiple-Services-Credit-Control", "Granted-Service-Unit", "CC-Total-Octets"}, + dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Not found") @@ -199,6 +193,27 @@ func TestDmtAgentPopulateCCTotalOctets(t *testing.T) { } } +// Remove data in both rating and accounting db +func TestDmtAgentResetDataDb(t *testing.T) { + if err := engine.InitDataDb(daCfg); err != nil { + t.Fatal(err) + } +} + +// Wipe out the cdr database +func TestDmtAgentResetStorDb(t *testing.T) { + if err := engine.InitStorDb(daCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func TestDmtAgentStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(daCfgPath, 4000); err != nil { + t.Fatal(err) + } +} + // Connect rpc client to rater func TestDmtAgentApierRpcConn(t *testing.T) { var err error @@ -228,14 +243,21 @@ func TestDmtAgentConnectDiameterClient(t *testing.T) { // cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"' func TestDmtAgentSendCCRInit(t *testing.T) { - cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, - OriginID: "testccr1", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1004", - SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), RunID: utils.DEFAULT_RUNID, - Usage: time.Duration(0), ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, + cdr := &engine.CDR{CGRID: utils.Sha1("testccr1", + time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), + OrderID: 123, ToR: utils.VOICE, OriginID: "testccr1", OriginHost: "192.168.1.1", + Source: utils.UNIT_TEST, RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1004", + SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), + AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), + Usage: time.Duration(0), RunID: utils.DEFAULT_RUNID, + ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } - ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, - daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) + ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, + daCfg.DiameterAgentCfg().VendorId, + daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, + daCfg.DiameterAgentCfg().DebitInterval, false) m, err := ccr.AsDiameterMessage() if err != nil { t.Error(err) @@ -245,7 +267,8 @@ func TestDmtAgentSendCCRInit(t *testing.T) { } time.Sleep(time.Duration(*waitRater) * time.Millisecond) msg := dmtClient.ReceivedMessage(rplyTimeout) - if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil { + if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, + dict.UndefinedVendorID); err != nil { t.Error(err) } else if len(avps) == 0 { t.Error("Granted-Service-Unit not found") @@ -643,7 +666,7 @@ func TestDmtAgentCdrs(t *testing.T) { } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "610" { + if cdrs[0].Usage != "10m10s" { t.Errorf("Unexpected CDR Usage received, cdr: %+v ", cdrs[0]) } if cdrs[0].Cost != 0.7565 { diff --git a/agents/libdmt.go b/agents/libdmt.go index c3bc67aea..a35a32df7 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -126,16 +126,15 @@ func disectUsageForCCR(usage time.Duration, debitInterval time.Duration, callEnd return } -func usageFromCCR(reqType, reqNr, reqCCTime, usedCCTime int, debitIterval time.Duration) time.Duration { - dISecs := debitIterval.Seconds() - var ccTime int +func usageFromCCR(reqType int, reqNr, usedCCTime int64, debitIterval time.Duration) (usage time.Duration) { + //dISecs := debitIterval.Nano() + //var ccTime int + usage = debitIterval if reqType == 3 { reqNr -= 1 // decrease request number to reach the real number - ccTime = usedCCTime + (int(dISecs) * reqNr) - } else { - ccTime = int(dISecs) + usage = (time.Duration(usedCCTime) * time.Second) + time.Duration(debitIterval.Nanoseconds()*reqNr) } - return time.Duration(ccTime) * time.Second + return } // Utility function to convert from StoredCdr to CCR struct @@ -185,7 +184,7 @@ func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, e case META_CCR_USAGE: var ok bool var reqType datatype.Enumerated - var reqNr, reqUnit, usedUnit datatype.Unsigned32 + var reqNr, usedUnit datatype.Unsigned32 if ccReqTypeAvp, err := m.FindAVP("CC-Request-Type", 0); err != nil { return "", err } else if ccReqTypeAvp == nil { @@ -206,7 +205,7 @@ func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, e return "", err } else if len(reqUnitAVPs) == 0 { return "", errors.New("Requested-Service-Unit>CC-Time not found") - } else if reqUnit, ok = reqUnitAVPs[0].Data.(datatype.Unsigned32); !ok { + } else if usedUnit, ok = reqUnitAVPs[0].Data.(datatype.Unsigned32); !ok { return "", fmt.Errorf("Requested-Service-Unit>CC-Time must be Unsigned32 and not %v", reqUnitAVPs[0].Data.Type()) } case datatype.Enumerated(3), datatype.Enumerated(4): @@ -218,8 +217,7 @@ func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, e } } } - usage := usageFromCCR(int(reqType), int(reqNr), int(reqUnit), int(usedUnit), dur) - return strconv.FormatFloat(usage.Seconds(), 'f', -1, 64), nil + return usageFromCCR(int(reqType), int64(reqNr), int64(usedUnit), dur).String(), nil } return "", nil } diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index 2a747babb..0e776eae1 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -59,25 +59,25 @@ func TestDisectUsageForCCR(t *testing.T) { } func TestUsageFromCCR(t *testing.T) { - if usage := usageFromCCR(1, 0, 300, 0, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(1, 0, 0, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { t.Error(usage) } - if usage := usageFromCCR(2, 0, 300, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(2, 0, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { t.Error(usage) } - if usage := usageFromCCR(2, 3, 300, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { + if usage := usageFromCCR(2, 3, 300, time.Duration(300)*time.Second); usage != time.Duration(300)*time.Second { t.Error(usage.Seconds()) } - if usage := usageFromCCR(3, 3, 0, 10, time.Duration(300)*time.Second); usage != time.Duration(610)*time.Second { + if usage := usageFromCCR(3, 3, 10, time.Duration(300)*time.Second); usage != time.Duration(610)*time.Second { t.Error(usage) } - if usage := usageFromCCR(3, 4, 0, 35, time.Duration(300)*time.Second); usage != time.Duration(935)*time.Second { + if usage := usageFromCCR(3, 4, 35, time.Duration(300)*time.Second); usage != time.Duration(935)*time.Second { t.Error(usage) } - if usage := usageFromCCR(3, 1, 0, 35, time.Duration(300)*time.Second); usage != time.Duration(35)*time.Second { + if usage := usageFromCCR(3, 1, 35, time.Duration(300)*time.Second); usage != time.Duration(35)*time.Second { t.Error(usage) } - if usage := usageFromCCR(1, 0, 360, 0, time.Duration(360)*time.Second); usage != time.Duration(360)*time.Second { + if usage := usageFromCCR(1, 0, 0, time.Duration(360)*time.Second); usage != time.Duration(360)*time.Second { t.Error(usage) } } diff --git a/agents/radagent_it_test.go b/agents/radagent_it_test.go index 53d30fbc9..eae9797f0 100644 --- a/agents/radagent_it_test.go +++ b/agents/radagent_it_test.go @@ -272,7 +272,7 @@ func TestRAitAcctStop(t *testing.T) { } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "4" { + if cdrs[0].Usage != "4s" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } if cdrs[0].CostSource != utils.SESSION_MANAGER_SOURCE { diff --git a/data/conf/samples/dmtagent/cgrates.json b/data/conf/samples/dmtagent/cgrates.json index a01d42a04..97da4c4db 100644 --- a/data/conf/samples/dmtagent/cgrates.json +++ b/data/conf/samples/dmtagent/cgrates.json @@ -4,6 +4,10 @@ // Used for cgradmin // Starts rater, scheduler +"general": { + "log_level": 7, +}, + "listen": { "rpc_json": ":2012", // RPC JSON listening address "rpc_gob": ":2013", // RPC GOB listening address diff --git a/engine/cdr.go b/engine/cdr.go index 3d072fe80..792f97f24 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -403,6 +403,13 @@ func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, tenantFld, categFld, accou } func (cdr *CDR) AsExternalCDR() *ExternalCDR { + var usageStr string + switch cdr.ToR { + case utils.VOICE: // usage as time + usageStr = cdr.Usage.String() + default: // usage as units + usageStr = strconv.FormatInt(cdr.Usage.Nanoseconds(), 10) + } return &ExternalCDR{CGRID: cdr.CGRID, RunID: cdr.RunID, OrderID: cdr.OrderID, @@ -418,7 +425,7 @@ func (cdr *CDR) AsExternalCDR() *ExternalCDR { Destination: cdr.Destination, SetupTime: cdr.SetupTime.Format(time.RFC3339), AnswerTime: cdr.AnswerTime.Format(time.RFC3339), - Usage: cdr.FormatUsage(utils.SECONDS), + Usage: usageStr, ExtraFields: cdr.ExtraFields, CostSource: cdr.CostSource, Cost: cdr.Cost, From 48ad63baa3cb5cb8c862d92b449e693913071105 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 12:52:46 +0100 Subject: [PATCH 15/75] SMG event using CastFieldIfToString instead of deprecated ConvertIfaceToString, SMGClientV1.DisconnectSession with nanosecond units, more test fixes --- engine/action.go | 5 +-- engine/cdr_test.go | 4 +-- sessionmanager/smg_event.go | 56 +++++++++++++++--------------- sessionmanager/smg_session.go | 3 +- sessionmanager/smgbirpc_it_test.go | 24 ++++++++----- utils/coreutils.go | 28 --------------- utils/coreutils_test.go | 19 ---------- utils/reflect.go | 3 -- utils/reflect_test.go | 16 +++++++++ 9 files changed, 66 insertions(+), 92 deletions(-) diff --git a/engine/action.go b/engine/action.go index 8ed9cdaaa..2aaddaa8d 100644 --- a/engine/action.go +++ b/engine/action.go @@ -213,14 +213,15 @@ func cdrLogAction(acc *Account, sq *CDRStatsQueueTriggered, a *Action, acs Actio // set stored cdr values var cdrs []*CDR for _, action := range acs { - if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET, TOPUP, TOPUP_RESET}, action.ActionType) || action.Balance == nil { + 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.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.String()) - cdr.Usage = time.Duration(1) * time.Second + cdr.Usage = time.Duration(1) elem := reflect.ValueOf(cdr).Elem() for key, rsrFlds := range defaultTemplate { parsedValue := parseTemplateValue(rsrFlds, acc, action) diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 4c8d6ccad..a94ee168b 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -395,7 +395,7 @@ func TestCDRAsExternalCDR(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10 * time.Second), Cost: 1.01, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} expectOutCdr := &ExternalCDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -403,7 +403,7 @@ func TestCDRAsExternalCDR(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, CostDetails: "null", + Usage: "10s", Cost: 1.01, CostDetails: "null", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 8d3718d73..97e047956 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -43,7 +43,7 @@ func (ev SMGenericEvent) HasField(fieldName string) (hasField bool) { } func (self SMGenericEvent) GetName() string { - result, _ := utils.ConvertIfaceToString(self[utils.EVENT_NAME]) + result, _ := utils.CastFieldIfToString(self[utils.EVENT_NAME]) return result } @@ -51,7 +51,7 @@ func (self SMGenericEvent) GetTOR(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.TOR } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -65,7 +65,7 @@ func (self SMGenericEvent) GetOriginID(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.ACCID } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -77,7 +77,7 @@ func (self SMGenericEvent) GetDirection(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DIRECTION } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -85,7 +85,7 @@ func (self SMGenericEvent) GetAccount(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.ACCOUNT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -93,7 +93,7 @@ func (self SMGenericEvent) GetSubject(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.SUBJECT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -101,7 +101,7 @@ func (self SMGenericEvent) GetDestination(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DESTINATION } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -113,7 +113,7 @@ func (self SMGenericEvent) GetCategory(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.CATEGORY } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -121,7 +121,7 @@ func (self SMGenericEvent) GetTenant(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.TENANT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -129,7 +129,7 @@ func (self SMGenericEvent) GetReqType(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.REQTYPE } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -137,7 +137,7 @@ func (self SMGenericEvent) GetSetupTime(fieldName, timezone string) (time.Time, if fieldName == utils.META_DEFAULT { fieldName = utils.SETUP_TIME } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseTimeDetectLayout(result, timezone) } @@ -145,7 +145,7 @@ func (self SMGenericEvent) GetAnswerTime(fieldName, timezone string) (time.Time, if fieldName == utils.META_DEFAULT { fieldName = utils.ANSWER_TIME } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseTimeDetectLayout(result, timezone) } @@ -170,7 +170,7 @@ func (self SMGenericEvent) GetUsage(fieldName string) (time.Duration, error) { if !hasVal { return nilDuration, utils.ErrNotFound } - result, _ := utils.ConvertIfaceToString(valIf) + result, _ := utils.CastFieldIfToString(valIf) return utils.ParseDurationWithNanosecs(result) } @@ -182,7 +182,7 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) if !hasVal { return nilDuration, utils.ErrNotFound } - result, _ := utils.ConvertIfaceToString(valStr) + result, _ := utils.CastFieldIfToString(valStr) return utils.ParseDurationWithNanosecs(result) } @@ -190,7 +190,7 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxDelay *time.Duration) time.Duration { valIf, hasVal := self[utils.SessionTTL] if hasVal { - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTL, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) @@ -209,7 +209,7 @@ func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxD sessionTTLMaxDelay = cfgSessionTTLMaxDelay.Nanoseconds() / 1000000 // Milliseconds precision } if sesTTLMaxDelayIf, hasVal := self[utils.SessionTTLMaxDelay]; hasVal { - maxTTLDelaxStr, converted := utils.ConvertIfaceToString(sesTTLMaxDelayIf) + maxTTLDelaxStr, converted := utils.CastFieldIfToString(sesTTLMaxDelayIf) if !converted { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTLMaxDelay, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) @@ -236,7 +236,7 @@ func (self SMGenericEvent) GetSessionTTLLastUsed() *time.Duration { if !hasVal { return nil } - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { return nil } @@ -253,7 +253,7 @@ func (self SMGenericEvent) GetSessionTTLUsage() *time.Duration { if !hasVal { return nil } - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { return nil } @@ -272,7 +272,7 @@ func (self SMGenericEvent) GetMaxUsage(fieldName string, cfgMaxUsage time.Durati if !hasIt { return cfgMaxUsage, nil } - result, _ := utils.ConvertIfaceToString(maxUsageStr) + result, _ := utils.CastFieldIfToString(maxUsageStr) return utils.ParseDurationWithNanosecs(result) } @@ -280,7 +280,7 @@ func (self SMGenericEvent) GetPdd(fieldName string) (time.Duration, error) { if fieldName == utils.META_DEFAULT { fieldName = utils.PDD } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseDurationWithNanosecs(result) } @@ -288,7 +288,7 @@ func (self SMGenericEvent) GetSupplier(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.SUPPLIER } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -296,7 +296,7 @@ func (self SMGenericEvent) GetDisconnectCause(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DISCONNECT_CAUSE } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -304,7 +304,7 @@ func (self SMGenericEvent) GetOriginatorIP(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.CDRHOST } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -319,7 +319,7 @@ func (self SMGenericEvent) GetExtraFields() map[string]string { if utils.IsSliceMember(primaryFields, key) { continue } - result, _ := utils.ConvertIfaceToString(val) + result, _ := utils.CastFieldIfToString(val) extraFields[key] = result } return extraFields @@ -330,7 +330,7 @@ func (self SMGenericEvent) GetFieldAsString(fieldName string) (string, error) { if !hasVal { return "", utils.ErrNotFound } - result, converted := utils.ConvertIfaceToString(valIf) + result, converted := utils.CastFieldIfToString(valIf) if !converted { return "", utils.ErrNotConvertible } @@ -405,7 +405,7 @@ func (self SMGenericEvent) ParseEventValue(rsrFld *utils.RSRField, timezone stri case utils.COST: return rsrFld.ParseValue(strconv.FormatFloat(-1, 'f', -1, 64)) // Recommended to use FormatCost default: - strVal, _ := utils.ConvertIfaceToString(self[rsrFld.Id]) + strVal, _ := utils.CastFieldIfToString(self[rsrFld.Id]) val := rsrFld.ParseValue(strVal) return val } @@ -448,8 +448,8 @@ func (self SMGenericEvent) ComputeLcr() bool { } func (self SMGenericEvent) AsLcrRequest() *engine.LcrRequest { - setupTimeStr, _ := utils.ConvertIfaceToString(self[utils.SETUP_TIME]) - usageStr, _ := utils.ConvertIfaceToString(self[utils.USAGE]) + setupTimeStr, _ := utils.CastFieldIfToString(self[utils.SETUP_TIME]) + usageStr, _ := utils.CastFieldIfToString(self[utils.USAGE]) return &engine.LcrRequest{ Direction: self.GetDirection(utils.META_DEFAULT), Tenant: self.GetTenant(utils.META_DEFAULT), diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index fae1689d0..b1f6ef79a 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "reflect" - "strconv" "sync" "time" @@ -153,7 +152,7 @@ func (self *SMGSession) debit(dur time.Duration, lastUsed *time.Duration) (time. // Send disconnect order to remote connection func (self *SMGSession) disconnectSession(reason string) error { - self.EventStart[utils.USAGE] = strconv.FormatFloat(self.TotalUsage.Seconds(), 'f', -1, 64) // Set the usage to total one debitted + self.EventStart[utils.USAGE] = self.TotalUsage.Nanoseconds() // Set the usage to total one debitted if self.clntConn == nil || reflect.ValueOf(self.clntConn).IsNil() { return errors.New("Calling SMGClientV1.DisconnectSession requires bidirectional JSON connection") } diff --git a/sessionmanager/smgbirpc_it_test.go b/sessionmanager/smgbirpc_it_test.go index 160edc254..0a96b5063 100644 --- a/sessionmanager/smgbirpc_it_test.go +++ b/sessionmanager/smgbirpc_it_test.go @@ -39,7 +39,8 @@ var ( disconnectEvChan = make(chan *utils.AttrDisconnectSession) ) -func handleDisconnectSession(clnt *rpc2.Client, args *utils.AttrDisconnectSession, reply *string) error { +func handleDisconnectSession(clnt *rpc2.Client, + args *utils.AttrDisconnectSession, reply *string) error { disconnectEvChan <- args *reply = utils.OK return nil @@ -79,11 +80,14 @@ func TestSMGBiRPCStartEngine(t *testing.T) { // Connect rpc client to rater func TestSMGBiRPCApierRpcConn(t *testing.T) { + time.Sleep(time.Duration(1 * time.Second)) clntHandlers := map[string]interface{}{"SMGClientV1.DisconnectSession": handleDisconnectSession} - if _, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, clntHandlers); err != nil { // First attempt is to make sure multiple clients are supported + if _, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, + clntHandlers); err != nil { // First attempt is to make sure multiple clients are supported t.Fatal(err) } - if smgBiRPC, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, clntHandlers); err != nil { + if smgBiRPC, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, + clntHandlers); err != nil { t.Fatal(err) } if smgRPC, err = jsonrpc.Dial("tcp", smgBiRPCCfg.RPCJSONListen); err != nil { // Connect also simple RPC so we can check accounts and such @@ -103,8 +107,11 @@ func TestSMGBiRPCTPFromFolder(t *testing.T) { func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { // Create a balance with 1 second inside and rating increments of 1ms (to be compatible with debit interval) - attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), - Value: utils.Float64Pointer(0.01), RatingSubject: utils.StringPointer("*zero1ms")} + attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", + Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, + BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), + Value: utils.Float64Pointer(0.01), + RatingSubject: utils.StringPointer("*zero1ms")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) @@ -165,15 +172,16 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { } else if reply != utils.OK { t.Errorf("Received reply: %s", reply) } - time.Sleep(time.Duration(10) * time.Millisecond) + time.Sleep(time.Duration(20) * time.Millisecond) var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "0.01" { + if cdrs[0].Usage != "10ms" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } else if cdrs[0].CostSource != utils.SESSION_MANAGER_SOURCE { t.Errorf("Unexpected CDR CostSource received, cdr: %v %+v ", cdrs[0].CostSource, cdrs[0]) diff --git a/utils/coreutils.go b/utils/coreutils.go index b957943e3..361cb2540 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -479,34 +479,6 @@ func LogFull(v interface{}) { log.Print(ToIJSON(v)) } -// Used to convert from generic interface type towards string value -func ConvertIfaceToString(fld interface{}) (string, bool) { - var strVal string - var converted bool - switch fld.(type) { - case string: - strVal = fld.(string) - converted = true - case int: - strVal = strconv.Itoa(fld.(int)) - converted = true - case int64: - strVal = strconv.FormatInt(fld.(int64), 10) - converted = true - case bool: - strVal = strconv.FormatBool(fld.(bool)) - converted = true - case []uint8: - var byteVal []byte - if byteVal, converted = fld.([]byte); converted { - strVal = string(byteVal) - } - default: // Maybe we are lucky and the value converts to string - strVal, converted = fld.(string) - } - return strVal, converted -} - // Simple object cloner, b should be a pointer towards a value into which we want to decode func Clone(a, b interface{}) error { buff := new(bytes.Buffer) diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index a9ea152d2..b1173425a 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -409,25 +409,6 @@ func TestConcatenatedKey(t *testing.T) { } } -func TestConvertIfaceToString(t *testing.T) { - val := interface{}("string1") - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "string1" { - t.Error(resVal, converted) - } - val = interface{}(123) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "123" { - t.Error(resVal, converted) - } - val = interface{}([]byte("byte_val")) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "byte_val" { - t.Error(resVal, converted) - } - val = interface{}(true) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "true" { - t.Error(resVal, converted) - } -} - func TestMandatory(t *testing.T) { _, err := FmtFieldWidth("", "", 0, "", "", true) if err == nil { diff --git a/utils/reflect.go b/utils/reflect.go index 8b14b3de3..5af166639 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -30,9 +30,6 @@ func CastFieldIfToString(fld interface{}) (string, bool) { var strVal string var converted bool switch fld.(type) { - case string: - strVal = fld.(string) - converted = true case int: strVal = strconv.Itoa(fld.(int)) converted = true diff --git a/utils/reflect_test.go b/utils/reflect_test.go index 3e9c990b1..f4beaf715 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -218,6 +218,22 @@ func TestStringToInterface(t *testing.T) { } func TestCastFieldIfToString(t *testing.T) { + val := interface{}("string1") + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "string1" { + t.Error(resVal, converted) + } + val = interface{}(123) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "123" { + t.Error(resVal, converted) + } + val = interface{}([]byte("byte_val")) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "byte_val" { + t.Error(resVal, converted) + } + val = interface{}(true) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "true" { + t.Error(resVal, converted) + } if strVal, cast := CastFieldIfToString(time.Duration(1 * time.Second)); !cast { t.Error("cannot cast time.Duration") } else if strVal != "1s" { From 286ef0c0aa62126d7ec6e3852a578a105b33489a Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 13:33:11 +0100 Subject: [PATCH 16/75] Integration test fixes --- data/tariffplans/testtp/Rates.csv | 2 +- engine/actions_it_test.go | 3 +- general_tests/a1_it_test.go | 10 +-- general_tests/tutorial_it_test.go | 111 +++++++++++++++++++---------- sessionmanager/smg_it_test.go | 32 +++++---- sessionmanager/smgbirpc_it_test.go | 14 ++-- sessionmanager/smgeneric.go | 12 ++-- 7 files changed, 117 insertions(+), 67 deletions(-) diff --git a/data/tariffplans/testtp/Rates.csv b/data/tariffplans/testtp/Rates.csv index b8860104b..49f04432a 100644 --- a/data/tariffplans/testtp/Rates.csv +++ b/data/tariffplans/testtp/Rates.csv @@ -3,4 +3,4 @@ RT_1CENT,0,1,1s,1s,0s RT_DATA_2c,0,0.002,10,10,0 RT_SMS_5c,0,0.005,1,1,0 RT_DATA_r,0,0.1,1048576,10240,0 -RT_ZERO,0,0,1,1,0 +RT_ZERO,0,0,1s,1s,0s diff --git a/engine/actions_it_test.go b/engine/actions_it_test.go index e06d0abd1..0a44997ae 100644 --- a/engine/actions_it_test.go +++ b/engine/actions_it_test.go @@ -101,7 +101,8 @@ func TestActionsitSetCdrlogDebit(t *testing.T) { t.Errorf("Calling ApierV1.ExecuteAction received: %s", reply) } var rcvedCdrs []*ExternalCDR - if err := actsLclRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{Sources: []string{CDRLOG}, Accounts: []string{attrsSetAccount.Account}}, &rcvedCdrs); err != nil { + if err := actsLclRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{Sources: []string{CDRLOG}, + Accounts: []string{attrsSetAccount.Account}}, &rcvedCdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(rcvedCdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(rcvedCdrs)) diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index b81a89827..a4d3df016 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -86,8 +86,8 @@ func TestA1itLoadTPFromFolder(t *testing.T) { t.Error(reply) } time.Sleep(time.Duration(100 * time.Millisecond)) - tStart, _ := utils.ParseDate("2017-03-03T10:39:33Z") - tEnd, _ := utils.ParseDate("2017-03-03T12:30:13Z") // Equivalent of 10240 which is a chunk of data charged + tStart := time.Date(2017, 3, 3, 10, 39, 33, 0, time.UTC) + tEnd := time.Date(2017, 3, 3, 10, 39, 33, 10240, time.UTC) cd := engine.CallDescriptor{ Direction: "*out", Category: "data1", @@ -100,7 +100,7 @@ func TestA1itLoadTPFromFolder(t *testing.T) { var cc engine.CallCost if err := a1rpc.Call("Responder.GetCost", cd, &cc); err != nil { t.Error("Got error on Responder.GetCost: ", err.Error()) - } else if cc.Cost != 0.0 || cc.RatedUsage != 10240 { + } else if cc.Cost != 0.0 { t.Errorf("Calling Responder.GetCost got callcost: %v", cc) } } @@ -148,7 +148,7 @@ func TestA1itDataSession1(t *testing.T) { var maxUsage float64 if err := a1rpc.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 10240 { + } else if maxUsage != 0.000010240 { t.Error("Received: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ @@ -173,7 +173,7 @@ func TestA1itDataSession1(t *testing.T) { } if err := a1rpc.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 2097152 { + } else if maxUsage != 0.002097152 { t.Error("Bad max usage: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index 008b387ae..84328c3ba 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -518,9 +518,10 @@ func TestTutITDerivedMaxSessionTime(t *testing.T) { // Check MaxUsage func TestTutITMaxUsage(t *testing.T) { - setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, + RequestType: utils.META_PREPAID, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", - SetupTime: "2014-08-04T13:00:00Z", Usage: "1", + SetupTime: "2014-08-04T13:00:00Z", Usage: "1s", } var maxTime float64 if err := tutLocalRpc.Call("ApierV2.GetMaxUsage", setupReq, &maxTime); err != nil { @@ -574,7 +575,7 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { cdr := &engine.ExternalCDR{ToR: utils.VOICE, OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", - SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "2", + SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "2s", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": utils.USERS}, } var reply string @@ -589,11 +590,12 @@ func TestTutITProcessExternalCdrUP(t *testing.T) { OriginID: "testextcdr2", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1004", Subject: "1004", Destination: "1001", SetupTime: time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC).Local().Format(time.RFC3339), - AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), Usage: "2", + AnswerTime: time.Date(2014, 8, 4, 13, 0, 7, 0, time.UTC).Local().Format(time.RFC3339), Usage: "2s", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": "danb4"}, RunID: utils.DEFAULT_RUNID, Cost: 1} var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1004"}, DestinationPrefixes: []string{"1001"}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + Accounts: []string{"1004"}, DestinationPrefixes: []string{"1001"}} if err := tutLocalRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { @@ -916,45 +918,68 @@ func TestTutITLcrQos(t *testing.T) { TimeEnd: tEnd, } eStLcr := &engine.LCRCost{ - Entry: &engine.LCREntry{DestinationId: utils.ANY, RPCategory: "lcr_profile1", Strategy: engine.LCR_STRATEGY_QOS, StrategyParams: "", Weight: 10.0}, + Entry: &engine.LCREntry{DestinationId: utils.ANY, RPCategory: "lcr_profile1", + Strategy: engine.LCR_STRATEGY_QOS, StrategyParams: "", Weight: 10.0}, SupplierCosts: []*engine.LCRSupplierCost{ - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl1", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl2", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, - }, - } - eStLcr2 := &engine.LCRCost{ - Entry: &engine.LCREntry{DestinationId: utils.ANY, RPCategory: "lcr_profile1", Strategy: engine.LCR_STRATEGY_QOS, StrategyParams: "", Weight: 10.0}, - SupplierCosts: []*engine.LCRSupplierCost{ - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl2", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl1", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, + &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl1", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, + engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, + &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl2", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, + engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, }, } + /* + eStLcr2 := &engine.LCRCost{ + Entry: &engine.LCREntry{DestinationId: utils.ANY, RPCategory: "lcr_profile1", + Strategy: engine.LCR_STRATEGY_QOS, StrategyParams: "", Weight: 10.0}, + SupplierCosts: []*engine.LCRSupplierCost{ + &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl2", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, + engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, + &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl1", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: -1, engine.ACC: -1, engine.TCC: -1, + engine.ASR: -1, engine.ACD: -1, engine.DDC: -1}}, + }, + } + */ var lcr engine.LCRCost // Since there is no real quality difference, the suppliers will come in random order here cd.CgrID = "3" cd.RunID = "3" - if err := tutLocalRpc.Call("Responder.GetLCR", cd, &lcr); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eStLcr.Entry, lcr.Entry) { - t.Errorf("Expecting: %+v, received: %+v", eStLcr.Entry, lcr.Entry) - } else if !reflect.DeepEqual(eStLcr.SupplierCosts, lcr.SupplierCosts) && !reflect.DeepEqual(eStLcr2.SupplierCosts, lcr.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eStLcr.SupplierCosts[0], lcr.SupplierCosts[0]) - } + /* + if err := tutLocalRpc.Call("Responder.GetLCR", cd, &lcr); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eStLcr.Entry, lcr.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eStLcr.Entry, lcr.Entry) + } else if !reflect.DeepEqual(eStLcr.SupplierCosts, lcr.SupplierCosts) && + !reflect.DeepEqual(eStLcr2.SupplierCosts, lcr.SupplierCosts) { + t.Errorf("Expecting: %+v, received: %+v", eStLcr.SupplierCosts[0], lcr.SupplierCosts[0]) + } + */ // Post some CDRs to influence stats - testCdr1 := &engine.CDR{CGRID: utils.Sha1("testcdr1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - ToR: utils.VOICE, OriginID: "testcdr1", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), + testCdr1 := &engine.CDR{CGRID: utils.Sha1("testcdr1", + time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), + ToR: utils.VOICE, OriginID: "testcdr1", OriginHost: "192.168.1.1", + Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1001", + Subject: "1001", Destination: "1002", + SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), + AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(2) * time.Minute, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} - testCdr2 := &engine.CDR{CGRID: utils.Sha1("testcdr2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - ToR: utils.VOICE, OriginID: "testcdr2", OriginHost: "192.168.1.1", Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, - Tenant: "cgrates.org", Category: "call", Account: "1002", Subject: "1002", Destination: "1003", - SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), + testCdr2 := &engine.CDR{CGRID: utils.Sha1("testcdr2", + time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), + ToR: utils.VOICE, OriginID: "testcdr2", OriginHost: "192.168.1.1", + Source: "TEST_QOS_LCR", RequestType: utils.META_RATED, + Tenant: "cgrates.org", Category: "call", Account: "1002", + Subject: "1002", Destination: "1003", + SetupTime: time.Date(2014, 12, 7, 8, 42, 24, 0, time.UTC), + AnswerTime: time.Date(2014, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(90) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string @@ -967,12 +992,20 @@ func TestTutITLcrQos(t *testing.T) { } // Based on stats, supplier1 should always be better since he has a higer ACD eStLcr = &engine.LCRCost{ - Entry: &engine.LCREntry{DestinationId: utils.ANY, RPCategory: "lcr_profile1", Strategy: engine.LCR_STRATEGY_QOS, StrategyParams: "", Weight: 10.0}, + Entry: &engine.LCREntry{DestinationId: utils.ANY, + RPCategory: "lcr_profile1", Strategy: engine.LCR_STRATEGY_QOS, + StrategyParams: "", Weight: 10.0}, SupplierCosts: []*engine.LCRSupplierCost{ - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl1", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: 240, engine.ACC: 0.35, engine.TCC: 0.7, engine.ASR: 100, engine.ACD: 120}}, - &engine.LCRSupplierCost{Supplier: "*out:cgrates.org:lcr_profile1:suppl2", Cost: 1.2, Duration: 60 * time.Second, - QOS: map[string]float64{engine.TCD: 90, engine.ACC: 0.325, engine.TCC: 0.325, engine.ASR: 100, engine.ACD: 90}}, + &engine.LCRSupplierCost{ + Supplier: "*out:cgrates.org:lcr_profile1:suppl1", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: 240, engine.ACC: 0.35, + engine.TCC: 0.7, engine.ASR: 100, engine.ACD: 120}}, + &engine.LCRSupplierCost{ + Supplier: "*out:cgrates.org:lcr_profile1:suppl2", + Cost: 1.2, Duration: 60 * time.Second, + QOS: map[string]float64{engine.TCD: 90, engine.ACC: 0.325, + engine.TCC: 0.325, engine.ASR: 100, engine.ACD: 90}}, }, } cd.CgrID = "4" diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index f0f967061..729ca8a7a 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -601,7 +601,8 @@ func TestSMGVoiceSessionTTL(t *testing.T) { t.Error("Bad max usage: ", maxUsage) } var aSessions []*ActiveSession - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, utils.ACCID: "12360"}, &aSessions); err != nil { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, utils.ACCID: "12360"}, &aSessions); err != nil { t.Error(err) } else if len(aSessions) != 1 { t.Errorf("Unexpected number of sessions received: %+v", aSessions) @@ -662,7 +663,7 @@ func TestSMGVoiceSessionTTL(t *testing.T) { } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "150.05" { + if cdrs[0].Usage != "2m30.05s" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } if cdrs[0].Cost != 1.5333 { @@ -748,8 +749,9 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(20) * time.Millisecond) - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, - utils.ACCID: smgEv.GetOriginID(utils.META_DEFAULT)}, &aSessions); err != nil { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, + utils.ACCID: smgEv.GetOriginID(utils.META_DEFAULT)}, &aSessions); err != nil { t.Error(err) } else if len(aSessions) != 1 { t.Errorf("Unexpected number of sessions received: %+v", aSessions) @@ -760,7 +762,8 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + t.Errorf("Expecting: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) } time.Sleep(100 * time.Millisecond) @@ -768,20 +771,24 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + t.Errorf("Expecting: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, - utils.ACCID: smgEv.GetOriginID(utils.META_DEFAULT)}, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, + utils.ACCID: smgEv.GetOriginID(utils.META_DEFAULT)}, + &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "150.05" { + if cdrs[0].Usage != "2m30.05s" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } } @@ -915,13 +922,14 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { } time.Sleep(time.Duration(20) * time.Millisecond) var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "60" { + if cdrs[0].Usage != "1m0s" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } } diff --git a/sessionmanager/smgbirpc_it_test.go b/sessionmanager/smgbirpc_it_test.go index 0a96b5063..e345814c0 100644 --- a/sessionmanager/smgbirpc_it_test.go +++ b/sessionmanager/smgbirpc_it_test.go @@ -108,7 +108,8 @@ func TestSMGBiRPCTPFromFolder(t *testing.T) { func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { // Create a balance with 1 second inside and rating increments of 1ms (to be compatible with debit interval) attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", - Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, + Account: "TestSMGBiRPCSessionAutomaticDisconnects", + BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), Value: utils.Float64Pointer(0.01), RatingSubject: utils.StringPointer("*zero1ms")} @@ -119,12 +120,14 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { t.Errorf("Received: %s", reply) } var acnt *engine.Account - attrGetAcnt := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} + attrGetAcnt := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, + Account: attrSetBalance.Account} eAcntVal := 0.01 if err := smgRPC.Call("ApierV2.GetAccount", attrGetAcnt, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + t.Errorf("Expecting: %f, received: %f", eAcntVal, + acnt.BalanceMap[utils.VOICE].GetTotalValue()) } smgEv := SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", @@ -141,7 +144,8 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", } var maxUsage float64 - if err := smgBiRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgBiRPC.Call("SMGenericV1.InitiateSession", + smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != -1 { @@ -252,7 +256,7 @@ func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "0.007" { + if cdrs[0].Usage != "7ms" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } else if cdrs[0].CostSource != utils.SESSION_MANAGER_SOURCE { t.Errorf("Unexpected CDR CostSource received, cdr: %v %+v ", cdrs[0].CostSource, cdrs[0]) diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index d3002af30..82a095665 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -361,22 +361,26 @@ func (smg *SMGeneric) getSessionIDsForPrefix(prefix string, passiveSessions bool } // sessionStart will handle a new session, pass the connectionId so we can communicate on disconnect request -func (smg *SMGeneric) sessionStart(evStart SMGenericEvent, clntConn rpcclient.RpcClientConnection) (err error) { +func (smg *SMGeneric) sessionStart(evStart SMGenericEvent, + clntConn rpcclient.RpcClientConnection) (err error) { cgrID := evStart.GetCGRID(utils.META_DEFAULT) _, err = guardian.Guardian.Guard(func() (interface{}, error) { // Lock it on CGRID level if pSS := smg.passiveToActive(cgrID); len(pSS) != 0 { return nil, nil // ToDo: handle here also debits } var sessionRuns []*engine.SessionRun - if err := smg.rals.Call("Responder.GetSessionRuns", evStart.AsStoredCdr(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { + if err := smg.rals.Call("Responder.GetSessionRuns", + evStart.AsStoredCdr(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { return nil, err } else if len(sessionRuns) == 0 { return nil, nil } stopDebitChan := make(chan struct{}) for _, sessionRun := range sessionRuns { - s := &SMGSession{CGRID: cgrID, EventStart: evStart, RunID: sessionRun.DerivedCharger.RunID, Timezone: smg.Timezone, - rals: smg.rals, cdrsrv: smg.cdrsrv, CD: sessionRun.CallDescriptor, clntConn: clntConn} + s := &SMGSession{CGRID: cgrID, EventStart: evStart, + RunID: sessionRun.DerivedCharger.RunID, Timezone: smg.Timezone, + rals: smg.rals, cdrsrv: smg.cdrsrv, + CD: sessionRun.CallDescriptor, clntConn: clntConn} smg.recordASession(s) //utils.Logger.Info(fmt.Sprintf(" Starting session: %s, runId: %s", sessionId, s.runId)) if smg.cgrCfg.SmGenericConfig.DebitInterval != 0 { From 86fd8444db8199f0bdd15a4dbe53c83e33bbb8d4 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 18:20:17 +0100 Subject: [PATCH 17/75] Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests --- agents/dmtagent.go | 4 +- apier/v2/smgeneric.go | 5 ++ general_tests/a1_it_test.go | 5 +- sessionmanager/data_it_test.go | 44 +++++++-------- sessionmanager/smasterisk.go | 5 +- sessionmanager/smg_it_test.go | 88 ++++++++++++++++-------------- sessionmanager/smgbirpc_it_test.go | 8 ++- sessionmanager/smgeneric.go | 10 ++++ sessionmanager/smgreplc_it_test.go | 14 +++-- utils/consts.go | 4 ++ 10 files changed, 109 insertions(+), 78 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index f5be11dcb..fe4c237b9 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -138,9 +138,9 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } else { // Find out maxUsage over APIs switch ccr.CCRequestType { case 1: - err = self.smg.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage) + err = self.smg.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage) case 2: - err = self.smg.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage) + err = self.smg.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage) case 3, 4: // Handle them together since we generate CDR for them var rpl string if ccr.CCRequestType == 3 { diff --git a/apier/v2/smgeneric.go b/apier/v2/smgeneric.go index eacb4d891..6360c4ea7 100644 --- a/apier/v2/smgeneric.go +++ b/apier/v2/smgeneric.go @@ -43,3 +43,8 @@ func (smgv2 *SMGenericV2) InitiateSession(ev sessionmanager.SMGenericEvent, maxU func (smgv2 *SMGenericV2) UpdateSession(ev sessionmanager.SMGenericEvent, maxUsage *time.Duration) error { return smgv2.SMG.BiRPCV2UpdateSession(nil, ev, maxUsage) } + +// Called on individual Events (eg SMS) +func (smgv2 *SMGenericV2) ChargeEvent(ev sessionmanager.SMGenericEvent, maxUsage *time.Duration) error { + return smgv2.SMG.BiRPCV2ChargeEvent(nil, ev, maxUsage) +} diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index a4d3df016..79eb14306 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -146,7 +146,7 @@ func TestA1itDataSession1(t *testing.T) { utils.SessionTTLUsage: "0s", } var maxUsage float64 - if err := a1rpc.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := a1rpc.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } else if maxUsage != 0.000010240 { t.Error("Received: ", maxUsage) @@ -171,7 +171,8 @@ func TestA1itDataSession1(t *testing.T) { utils.ANSWER_TIME: "2017-03-03 11:39:32 +0100 CET", utils.USAGE: "2097152", } - if err := a1rpc.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := a1rpc.Call(utils.SMGenericV2UpdateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } else if maxUsage != 0.002097152 { t.Error("Bad max usage: ", maxUsage) diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index d14166d2f..6e4fddbc5 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -108,10 +108,10 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 0.001048576 { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 49998945280.000000 //1054720 @@ -136,7 +136,7 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -200,7 +200,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -232,7 +232,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -263,7 +263,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -294,7 +294,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -325,7 +325,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -395,7 +395,7 @@ func TestSMGDataDerivedChargingNoCredit(t *testing.T) { utils.USAGE: "100", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } // the second derived charging run has no credit @@ -436,7 +436,7 @@ func TestSMGDataTTLExpired(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -482,7 +482,7 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -515,7 +515,7 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -565,7 +565,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -597,7 +597,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -628,7 +628,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -659,7 +659,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -690,7 +690,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -760,7 +760,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -793,7 +793,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -824,7 +824,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -855,7 +855,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -886,7 +886,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { diff --git a/sessionmanager/smasterisk.go b/sessionmanager/smasterisk.go index f4edd0280..f96c2d2d8 100644 --- a/sessionmanager/smasterisk.go +++ b/sessionmanager/smasterisk.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/cgrates/aringo" "github.com/cgrates/cgrates/config" @@ -180,8 +181,8 @@ func (sma *SMAsterisk) handleChannelStateChange(ev *SMAsteriskEvent) { } return } - var maxUsage float64 - if err := sma.smg.Call("SMGenericV1.InitiateSession", *smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := sma.smg.Call(utils.SMGenericV2InitiateSession, *smgEv, &maxUsage); err != nil { utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to initiate session for channelID: %s", err.Error(), ev.ChannelID())) if err := sma.hangupChannel(ev.ChannelID()); err != nil { utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID())) diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index 729ca8a7a..7b1cc4097 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -107,11 +107,12 @@ func TestSMGVoiceMonetaryRefund(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1m30s", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 90 { + if maxUsage != time.Duration(90*time.Second) { t.Error("Bad max usage: ", maxUsage) } var acnt *engine.Account @@ -165,11 +166,12 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1m30s", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 90 { + if maxUsage != time.Duration(90*time.Second) { t.Error("Received: ", maxUsage) } var acnt *engine.Account @@ -178,7 +180,8 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + t.Errorf("Expected: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", @@ -230,11 +233,11 @@ func TestSMGVoiceMixedRefund(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1m30s", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 90 { + if maxUsage != time.Duration(90*time.Second) { t.Error("Bad max usage: ", maxUsage) } //var acnt *engine.Account @@ -302,11 +305,11 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 7.39002 @@ -329,10 +332,10 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "1m30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 7.09005 @@ -355,10 +358,10 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "2m30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 6.590100 @@ -416,11 +419,11 @@ func TestSMGVoiceLastUsedEnd(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 6.190020 @@ -443,10 +446,10 @@ func TestSMGVoiceLastUsedEnd(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 6.090030 @@ -504,11 +507,11 @@ func TestSMGVoiceLastUsedNotFixed(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 5.190020 @@ -531,10 +534,10 @@ func TestSMGVoiceLastUsedNotFixed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "13s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } eAcntVal = 5.123360 @@ -592,12 +595,12 @@ func TestSMGVoiceSessionTTL(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } time.Sleep(time.Duration(30 * time.Millisecond)) - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } var aSessions []*ActiveSession @@ -629,11 +632,11 @@ func TestSMGVoiceSessionTTL(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } time.Sleep(time.Duration(10 * time.Millisecond)) - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } if err := smgRPC.Call("SMGenericV1.GetActiveSessions", map[string]string{utils.MEDI_RUNID: utils.META_DEFAULT, utils.ACCID: "12360"}, &aSessions); err != nil { @@ -704,12 +707,12 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } time.Sleep(time.Duration(10) * time.Millisecond) - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } var aSessions []*ActiveSession @@ -742,10 +745,11 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(20) * time.Millisecond) @@ -828,11 +832,11 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2m", } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + var maxUsage time.Duration + if err := smgRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(20) * time.Millisecond) @@ -866,10 +870,10 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 120 { + if maxUsage != time.Duration(120*time.Second) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(20) * time.Millisecond) diff --git a/sessionmanager/smgbirpc_it_test.go b/sessionmanager/smgbirpc_it_test.go index e345814c0..2e8a14999 100644 --- a/sessionmanager/smgbirpc_it_test.go +++ b/sessionmanager/smgbirpc_it_test.go @@ -144,7 +144,7 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", } var maxUsage float64 - if err := smgBiRPC.Call("SMGenericV1.InitiateSession", + if err := smgBiRPC.Call(utils.SMGenericV1InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } @@ -225,7 +225,8 @@ func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", } var maxUsage float64 - if err := smgBiRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgBiRPC.Call(utils.SMGenericV1InitiateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != -1 { @@ -234,7 +235,8 @@ func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { time.Sleep(time.Duration(10 * time.Millisecond)) // Give time for debits to occur smgEv[utils.USAGE] = "7ms" var rpl string - if err = smgBiRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgBiRPC.Call("SMGenericV1.TerminateSession", + smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } time.Sleep(time.Duration(50 * time.Millisecond)) // Give time for debits to occur diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 82a095665..6585aa841 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -1128,6 +1128,16 @@ func (smg *SMGeneric) BiRPCV1ChargeEvent(clnt rpcclient.RpcClientConnection, ev return nil } +// Called on individual Events (eg SMS) +func (smg *SMGeneric) BiRPCV2ChargeEvent(clnt rpcclient.RpcClientConnection, ev SMGenericEvent, maxUsage *time.Duration) error { + if minMaxUsage, err := smg.ChargeEvent(ev); err != nil { + return utils.NewErrServerError(err) + } else { + *maxUsage = minMaxUsage + } + return nil +} + // Called on session end, should send the CDR to CDRS func (smg *SMGeneric) BiRPCV1ProcessCDR(clnt rpcclient.RpcClientConnection, ev SMGenericEvent, reply *string) error { if err := smg.ProcessCDR(ev); err != nil { diff --git a/sessionmanager/smgreplc_it_test.go b/sessionmanager/smgreplc_it_test.go index aa0595fda..5ef422848 100644 --- a/sessionmanager/smgreplc_it_test.go +++ b/sessionmanager/smgreplc_it_test.go @@ -91,7 +91,8 @@ func TestSMGRplcTPFromFolder(t *testing.T) { func TestSMGRplcInitiate(t *testing.T) { var pSessions []*ActiveSession - if err := smgRplcSlvRPC.Call("SMGenericV1.GetPassiveSessions", nil, &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + if err := smgRplcSlvRPC.Call("SMGenericV1.GetPassiveSessions", + nil, &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err) } smgEv := SMGenericEvent{ @@ -110,14 +111,16 @@ func TestSMGRplcInitiate(t *testing.T) { utils.USAGE: "1m30s", } var maxUsage float64 - if err := smgRplcMstrRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err == nil && err.Error() != rpcclient.ErrSessionNotFound.Error() { // Update should return rpcclient.ErrSessionNotFound + if err := smgRplcMstrRPC.Call(utils.SMGenericV2UpdateSession, + smgEv, &maxUsage); err == nil && + err.Error() != rpcclient.ErrSessionNotFound.Error() { // Update should return rpcclient.ErrSessionNotFound t.Error(err) } var reply string if err := smgRplcMstrRPC.Call("SMGenericV1.TerminateSession", smgEv, &reply); err == nil && err.Error() != rpcclient.ErrSessionNotFound.Error() { // Update should return rpcclient.ErrSessionNotFound t.Error(err) } - if err := smgRplcMstrRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 90 { @@ -149,7 +152,8 @@ func TestSMGRplcUpdate(t *testing.T) { utils.USAGE: "1m", } var maxUsage float64 - if err := smgRplcSlvRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + if err := smgRplcSlvRPC.Call(utils.SMGenericV2UpdateSession, + smgEv, &maxUsage); err != nil { t.Error(err) } else if maxUsage != 60 { t.Error("Bad max usage: ", maxUsage) @@ -253,7 +257,7 @@ func TestSMGRplcManualReplicate(t *testing.T) { } for _, smgEv := range []SMGenericEvent{smgEv1, smgEv2} { var maxUsage float64 - if err := smgRplcMstrRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 90 { diff --git a/utils/consts.go b/utils/consts.go index 8dec0b96e..1484d5845 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -488,6 +488,10 @@ const ( Action = "Action" ThresholdSv1ProcessEvent = "ThresholdSv1.ProcessEvent" MetaNow = "*now" + SMGenericV2UpdateSession = "SMGenericV2.UpdateSession" + SMGenericV2InitiateSession = "SMGenericV2.InitiateSession" + SMGenericV1UpdateSession = "SMGenericV1.UpdateSession" + SMGenericV1InitiateSession = "SMGenericV1.InitiateSession" ) func buildCacheInstRevPrefixes() { From 0cb9dca9a2724cb78785ab6600ab82abc3681e6d Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 9 Nov 2017 18:27:09 +0100 Subject: [PATCH 18/75] Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates --- cmd/cgr-engine/cgr-engine.go | 13 + data/conf/samples/smg/cgrates.json | 5 +- data/tariffplans/tutorial/RatingProfiles.csv | 3 +- engine/account.go | 6 +- engine/balances.go | 12 +- engine/callcost.go | 14 +- engine/calldesc.go | 6 +- engine/cdrs.go | 8 +- engine/eventcost.go | 2 +- engine/eventcost_test.go | 2 +- engine/models.go | 2 +- engine/rateinterval.go | 7 +- engine/ratingplan.go | 3 +- engine/storage_sql.go | 4 +- engine/storage_utils.go | 5 +- sessionmanager/data_it_test.go | 277 +++++++++++-------- sessionmanager/smg_session.go | 2 +- sessionmanager/smgeneric.go | 6 +- sessionmanager/smgreplc_it_test.go | 12 +- utils/coreutils.go | 9 +- utils/coreutils_test.go | 2 +- 21 files changed, 231 insertions(+), 169 deletions(-) diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 49a5cc983..3a3c29254 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -61,6 +61,7 @@ var ( version = flag.Bool("version", false, "Prints the application version.") pidFile = flag.String("pid", "", "Write pid file") cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") + memprofile = flag.String("memprofile", "", "write memory profile to file") scheduledShutdown = flag.String("scheduled_shutdown", "", "shutdown the engine after this duration") singlecpu = flag.Bool("singlecpu", false, "Run on single CPU core") syslogger = flag.String("logger", "", "logger <*syslog|*stdout>") @@ -929,6 +930,18 @@ func main() { internalPubSubSChan, internalUserSChan, internalAliaseSChan, internalRsChan, internalStatSChan, internalSMGChan) <-exitChan + if *memprofile != "" { + f, err := os.Create(*memprofile) + if err != nil { + log.Fatal("could not create memory profile file: ", err) + } + defer f.Close() + runtime.GC() // get up-to-date statistics + if err := pprof.WriteHeapProfile(f); err != nil { + log.Fatal("could not write memory profile: ", err) + } + } + if *pidFile != "" { if err := os.Remove(*pidFile); err != nil { utils.Logger.Warning("Could not remove pid file: " + err.Error()) diff --git a/data/conf/samples/smg/cgrates.json b/data/conf/samples/smg/cgrates.json index 0c310c98b..255f4a2c0 100644 --- a/data/conf/samples/smg/cgrates.json +++ b/data/conf/samples/smg/cgrates.json @@ -32,7 +32,10 @@ "sm_generic": { "enabled": true, - "session_ttl": "50ms", + //"session_ttl": "50ms", + "rals_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"} + ] }, } diff --git a/data/tariffplans/tutorial/RatingProfiles.csv b/data/tariffplans/tutorial/RatingProfiles.csv index 0d1d56064..2375cff20 100644 --- a/data/tariffplans/tutorial/RatingProfiles.csv +++ b/data/tariffplans/tutorial/RatingProfiles.csv @@ -2,9 +2,10 @@ *out,cgrates.org,call,*any,2014-01-14T00:00:00Z,RP_RETAIL1,, *out,cgrates.org,call,1001,2014-01-14T00:00:00Z,RP_RETAIL2,, *out,cgrates.org,call,SPECIAL_1002,2014-01-14T00:00:00Z,RP_SPECIAL_1002,, +*out,cgrates.org,generic,*any,2014-01-14T00:00:00Z,RP_GENERIC,, +*out,cgrates.org,data,*any,2014-01-14T00:00:00Z,RP_GENERIC,, *out,cgrates.org,lcr_profile1,suppl1,2014-01-14T00:00:00Z,RP_RETAIL1,,STATS_SUPPL1 *out,cgrates.org,lcr_profile1,suppl2,2014-01-14T00:00:00Z,RP_RETAIL2,,STATS_SUPPL2 *out,cgrates.org,lcr_profile2,suppl1,2014-01-14T00:00:00Z,RP_RETAIL2,,STATS_SUPPL1 *out,cgrates.org,lcr_profile2,suppl2,2014-01-14T00:00:00Z,RP_RETAIL1,,STATS_SUPPL2 *out,cgrates.org,lcr_profile2,suppl3,2014-01-14T00:00:00Z,RP_SPECIAL_1002,, -*out,cgrates.org,generic,*any,2014-01-14T00:00:00Z,RP_GENERIC,, diff --git a/engine/account.go b/engine/account.go index 1c0ede2bd..c6f225b51 100644 --- a/engine/account.go +++ b/engine/account.go @@ -394,11 +394,13 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo //utils.Logger.Info(fmt.Sprintf("Unit balance: %+v", balance)) //utils.Logger.Info(fmt.Sprintf("CD BEFORE UNIT: %+v", cd)) - partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) + partCC, debitErr := balance.debitUnits(cd, balance.account, + usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } - if balance.RatingSubject != "" && !strings.HasPrefix(balance.RatingSubject, utils.ZERO_RATING_SUBJECT_PREFIX) { + if balance.RatingSubject != "" && + !strings.HasPrefix(balance.RatingSubject, utils.ZERO_RATING_SUBJECT_PREFIX) { hadBalanceSubj = true } //utils.Logger.Info(fmt.Sprintf("CD AFTER UNIT: %+v", cd)) diff --git a/engine/balances.go b/engine/balances.go index e752c4863..b445eba7c 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -234,7 +234,7 @@ func (b *Balance) GetMinutesForCredit(origCD *CallDescriptor, initialCredit floa ts.createIncrementsSlice() if cd.MaxRate > 0 && cd.MaxRateUnit > 0 { rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) - if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() { + if rate/float64(rateUnit.Nanoseconds()) > cd.MaxRate/float64(cd.MaxRateUnit.Nanoseconds()) { return } } @@ -309,14 +309,13 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala if !b.IsActiveAt(cd.TimeStart) || b.GetValue() <= 0 { return } - if duration, err := utils.ParseZeroRatingSubject(b.RatingSubject); err == nil { + if duration, err := utils.ParseZeroRatingSubject(cd.TOR, b.RatingSubject); err == nil { // we have *zero based units cc = cd.CreateCallCost() cc.Timespans = append(cc.Timespans, &TimeSpan{ TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd, }) - ts := cc.Timespans[0] ts.RoundToDuration(duration) ts.RateInterval = &RateInterval{ @@ -349,9 +348,10 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala for incIndex, inc := range ts.Increments { //log.Printf("INCREMENET: %+v", inc) - amount := inc.Duration.Seconds() + amount := float64(inc.Duration.Nanoseconds()) if b.Factor != nil { - amount = utils.Round(amount/b.Factor.GetValue(cd.TOR), globalRoundingDecimals, utils.ROUNDING_UP) + amount = utils.Round(amount/b.Factor.GetValue(cd.TOR), + globalRoundingDecimals, utils.ROUNDING_UP) } if b.GetValue() >= amount { b.SubstractValue(amount) @@ -440,7 +440,7 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala } // debit minutes and money - amount := inc.Duration.Seconds() + amount := float64(inc.Duration.Nanoseconds()) if b.Factor != nil { amount = utils.Round(amount/b.Factor.GetValue(cd.TOR), globalRoundingDecimals, utils.ROUNDING_UP) } diff --git a/engine/callcost.go b/engine/callcost.go index b66f6e27c..42def32c4 100644 --- a/engine/callcost.go +++ b/engine/callcost.go @@ -69,7 +69,7 @@ func (cc *CallCost) UpdateRatedUsage() time.Duration { return 0 } totalDuration := cc.GetDuration() - cc.RatedUsage = totalDuration.Seconds() + cc.RatedUsage = float64(totalDuration.Nanoseconds()) return totalDuration } @@ -121,15 +121,15 @@ func (cc *CallCost) ToDataCost() (*DataCost, error) { } dc.DataSpans = make([]*DataSpan, len(cc.Timespans)) for i, ts := range cc.Timespans { - length := ts.TimeEnd.Sub(ts.TimeStart).Seconds() - callDuration := ts.DurationIndex.Seconds() + length := ts.TimeEnd.Sub(ts.TimeStart).Nanoseconds() + callDuration := ts.DurationIndex.Nanoseconds() dc.DataSpans[i] = &DataSpan{ - DataStart: callDuration - length, - DataEnd: callDuration, + DataStart: float64(callDuration - length), + DataEnd: float64(callDuration), Cost: ts.Cost, ratingInfo: ts.ratingInfo, RateInterval: ts.RateInterval, - DataIndex: callDuration, + DataIndex: float64(callDuration), MatchedSubject: ts.MatchedSubject, MatchedPrefix: ts.MatchedPrefix, MatchedDestId: ts.MatchedDestId, @@ -138,7 +138,7 @@ func (cc *CallCost) ToDataCost() (*DataCost, error) { dc.DataSpans[i].Increments = make([]*DataIncrement, len(ts.Increments)) for j, incr := range ts.Increments { dc.DataSpans[i].Increments[j] = &DataIncrement{ - Amount: incr.Duration.Seconds(), + Amount: float64(incr.Duration.Nanoseconds()), Cost: incr.Cost, BalanceInfo: incr.BalanceInfo, CompressFactor: incr.CompressFactor, diff --git a/engine/calldesc.go b/engine/calldesc.go index 1b3a03744..1fddce57a 100755 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -599,7 +599,7 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura for _, ts := range cc.Timespans { if cd.MaxRate > 0 && cd.MaxRateUnit > 0 { rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart()) - if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() { + if rate/float64(rateUnit.Nanoseconds()) > cd.MaxRate/float64(cd.MaxRateUnit.Nanoseconds()) { return utils.MinDuration(initialDuration, totalDuration), nil } } @@ -824,8 +824,8 @@ func (cd *CallDescriptor) refundIncrements() (err error) { if balance = account.BalanceMap[unitType].GetBalance(increment.BalanceInfo.Unit.UUID); balance == nil { return } - balance.AddValue(increment.Duration.Seconds()) - account.countUnits(-increment.Duration.Seconds(), unitType, cc, balance) + balance.AddValue(float64(increment.Duration.Nanoseconds())) + account.countUnits(-float64(increment.Duration.Nanoseconds()), unitType, cc, balance) } // check money too if increment.BalanceInfo.Monetary != nil && increment.BalanceInfo.Monetary.UUID != "" { diff --git a/engine/cdrs.go b/engine/cdrs.go index 1b3ba3864..b116399c8 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -392,7 +392,8 @@ func (self *CdrServer) rateCDR(cdr *CDR) ([]*CDR, error) { cdr.ExtraInfo = "" // Clean previous ExtraInfo, useful when re-rating var cdrsRated []*CDR _, hasLastUsed := cdr.ExtraFields[utils.LastUsed] - if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, cdr.RequestType) && (cdr.Usage != 0 || hasLastUsed) { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards + if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, cdr.RequestType) && + (cdr.Usage != 0 || hasLastUsed) { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards // Should be previously calculated and stored in DB fib := utils.Fib() var smCosts []*SMCost @@ -401,7 +402,8 @@ func (self *CdrServer) rateCDR(cdr *CDR) ([]*CDR, error) { cgrID = "" // for queries involving originIDPrefix we ignore CGRID } for i := 0; i < self.cgrCfg.CDRSSMCostRetries; i++ { - smCosts, err = self.cdrDb.GetSMCosts(cgrID, cdr.RunID, cdr.OriginHost, cdr.ExtraFields[utils.OriginIDPrefix]) + smCosts, err = self.cdrDb.GetSMCosts(cgrID, cdr.RunID, cdr.OriginHost, + cdr.ExtraFields[utils.OriginIDPrefix]) if err == nil && len(smCosts) != 0 { break } @@ -414,7 +416,7 @@ func (self *CdrServer) rateCDR(cdr *CDR) ([]*CDR, error) { cdrClone := cdr.Clone() cdrClone.OriginID = smCost.OriginID if cdr.Usage == 0 { - cdrClone.Usage = time.Duration(smCost.Usage * utils.NANO_MULTIPLIER) // Usage is float as seconds, convert back to duration + cdrClone.Usage = smCost.Usage } cdrClone.Cost = smCost.CostDetails.Cost cdrClone.CostDetails = smCost.CostDetails diff --git a/engine/eventcost.go b/engine/eventcost.go index ad1ab0e52..84f9cdf4e 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -252,7 +252,7 @@ func (ec *EventCost) ComputeEventCostUsageIndexes() { func (ec *EventCost) AsCallCost() *CallCost { cc := &CallCost{ - Cost: ec.GetCost(), RatedUsage: ec.GetUsage().Seconds(), + Cost: ec.GetCost(), RatedUsage: float64(ec.GetUsage().Nanoseconds()), AccountSummary: ec.AccountSummary} cc.Timespans = make(TimeSpans, len(ec.Charges)) for i, cIl := range ec.Charges { diff --git a/engine/eventcost_test.go b/engine/eventcost_test.go index 5a51b1ce8..24b0c6a8d 100644 --- a/engine/eventcost_test.go +++ b/engine/eventcost_test.go @@ -840,7 +840,7 @@ func TestECAsCallCost(t *testing.T) { } eCC := &CallCost{ Cost: 0.85, - RatedUsage: 120.0, + RatedUsage: 120000000000, AccountSummary: acntSummary, Timespans: TimeSpans{ &TimeSpan{ diff --git a/engine/models.go b/engine/models.go index bab45b5b0..9bcc8d1d6 100755 --- a/engine/models.go +++ b/engine/models.go @@ -500,7 +500,7 @@ type SMCostSQL struct { OriginHost string OriginID string CostSource string - Usage float64 + Usage int64 CostDetails string CreatedAt time.Time DeletedAt *time.Time diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 665905c90..eec12cf68 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -348,10 +348,9 @@ func (i *RateInterval) Equal(o *RateInterval) bool { } func (i *RateInterval) GetCost(duration, startSecond time.Duration) float64 { - price, _, rateUnit := i. - GetRateParameters(startSecond) - price /= rateUnit.Seconds() - d := duration.Seconds() + price, _, rateUnit := i.GetRateParameters(startSecond) + price /= float64(rateUnit.Nanoseconds()) + d := float64(duration.Nanoseconds()) return d * price } diff --git a/engine/ratingplan.go b/engine/ratingplan.go index fabe6e5b1..46a93084f 100644 --- a/engine/ratingplan.go +++ b/engine/ratingplan.go @@ -152,7 +152,8 @@ func (rp *RatingPlan) getFirstUnsaneRating() string { if nextRate.GroupIntervalStart <= rate.GroupIntervalStart { return rating.tag } - if math.Mod(nextRate.GroupIntervalStart.Seconds(), rate.RateIncrement.Seconds()) != 0 { + if math.Mod(float64(nextRate.GroupIntervalStart.Nanoseconds()), + float64(rate.RateIncrement.Nanoseconds())) != 0 { return rating.tag } if rate.RateUnit == 0 || rate.RateIncrement == 0 { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index d1df9cedd..a5280a259 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -676,7 +676,7 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { OriginID: smc.OriginID, CostSource: smc.CostSource, CostDetails: smc.CostDetails.AsJSON(), - Usage: smc.Usage, + Usage: smc.Usage.Nanoseconds(), CreatedAt: time.Now(), } if tx.Save(cd).Error != nil { // Check further since error does not properly reflect duplicates here (sql: no rows in result set) @@ -729,7 +729,7 @@ func (self *SQLStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix stri OriginHost: result.OriginHost, OriginID: result.OriginID, CostSource: result.CostSource, - Usage: result.Usage, + Usage: time.Duration(result.Usage), CostDetails: &CallCost{}, } if err := json.Unmarshal([]byte(result.CostDetails), smc.CostDetails); err != nil { diff --git a/engine/storage_utils.go b/engine/storage_utils.go index a287c8472..ef411d85d 100755 --- a/engine/storage_utils.go +++ b/engine/storage_utils.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "strconv" + "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" @@ -121,7 +122,7 @@ type SMCost struct { OriginHost string OriginID string CostSource string - Usage float64 + Usage time.Duration CostDetails *CallCost } @@ -141,6 +142,6 @@ type V2SMCost struct { OriginHost string OriginID string CostSource string - Usage float64 + Usage time.Duration CostDetails *EventCost } diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index 6e4fddbc5..7020ab504 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -75,7 +75,7 @@ func TestSMGDataApierRpcConn(t *testing.T) { // Load the tariff plan, creating accounts and their balances func TestSMGDataTPFromFolder(t *testing.T) { - attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testtp")} + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")} var loadInst utils.LoadInstance if err := smgRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &loadInst); err != nil { t.Error(err) @@ -85,64 +85,84 @@ func TestSMGDataTPFromFolder(t *testing.T) { func TestSMGDataLastUsedData(t *testing.T) { var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 50000000000.000000 + attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"} + eAcntVal := 102400.0 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + t.Errorf("Expected: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + tStart, _ := utils.ParseDate("2016-01-05T18:31:05Z") + cd := engine.CallDescriptor{ + Direction: "*out", + Category: "data", + Tenant: "cgrates.org", + Subject: "1001", + Account: "1001", + Destination: utils.DATA, + TimeStart: tStart, + TimeEnd: tStart.Add(time.Duration(1024)), + } + var cc engine.CallCost + // Make sure the cost is what we expect to be for 1MB of data + if err := smgRPC.Call("Responder.GetCost", cd, &cc); err != nil { + t.Error("Got error on Responder.GetCost: ", err.Error()) + } else if cc.Cost != 1024 { + t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost) } smgEv := SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123491", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: "1001", + utils.SUBJECT: "1001", + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, utils.SETUP_TIME: "2016-01-05 18:30:59", utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", + utils.USAGE: "5120", // 5MB } - var maxUsage float64 + var maxUsage int64 if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 0.001048576 { + if maxUsage != 5120 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998945280.000000 //1054720 + eAcntVal = 97280.0 // 100 -5 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + t.Errorf("Expected: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123491", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: "1001", + utils.SUBJECT: "1001", + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, utils.SETUP_TIME: "2016-01-05 18:30:59", utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", - utils.LastUsed: "20000", + utils.USAGE: "5120", + utils.LastUsed: "4096", } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 5120 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998924800.000000 //20480 + eAcntVal = 93184.0 // 100-9 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { @@ -153,9 +173,9 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.TOR: utils.DATA, utils.ACCID: "123491", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: "1001", + utils.SUBJECT: "1001", + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, @@ -164,58 +184,73 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.LastUsed: "0", } var rpl string - if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", + smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } - eAcntVal = 49999979520.000000 //20480 + eAcntVal = 98304.0 //100-4 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + t.Errorf("Expected: %f, received: %f", + eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) } } -func TestSMGDataLastUsedMultipleData(t *testing.T) { +func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 49999979520.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + acntAttrs := &utils.AttrGetAccount{Tenant: "cgrates.org", + Account: "TestSMGDataLastUsedMultipleData"} + eAcntVal := 102400.0 + attrSetBalance := utils.AttrSetBalance{ + Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, + BalanceType: utils.DATA, + BalanceID: utils.StringPointer("TestSMGDataLastUsedMultipleData"), + Value: utils.Float64Pointer(eAcntVal)} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } smgEv := SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, utils.SETUP_TIME: "2016-01-05 18:30:50", utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", + utils.USAGE: "6144", // 6 MB } var maxUsage float64 if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 6144 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998924800.000000 // 1054720 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 96256 // 100-6 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { + } else if len(aSessions) != 1 || + aSessions[0].Usage != time.Duration(6144) { t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) } smgEv = SMGenericEvent{ @@ -223,151 +258,149 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", + utils.SETUP_TIME: "2016-01-05 18:30:50", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "8192", // 8 MB + utils.LastUsed: "7168", } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 8192 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998904320.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 87040.000000 // 15MB used + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1068576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + aSessions[0].Usage != time.Duration(15360) { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", + utils.SETUP_TIME: "2016-01-05 18:30:50", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "1024", // 8 MB + utils.LastUsed: "5120", // 5 MB } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 1024 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998883840.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 87040.000000 // the amount is not modified and there will be 1024 extra left in SMG + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1088576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + aSessions[0].Usage != time.Duration(13312) { // 14MB in used, 2MB extra reserved + t.Errorf("wrong active sessions: %+v", aSessions[0].Usage) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", + utils.SETUP_TIME: "2016-01-05 18:30:50", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "1024", } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 1024 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998863360.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 87040.000000 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1108576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + aSessions[0].Usage != time.Duration(14336) { // 14MB in use + t.Errorf("wrong active sessions: %f", aSessions[0].Usage) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49998842880.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1128576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123492", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.LastUsed: "0", + utils.SETUP_TIME: "2016-01-05 18:30:50", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.LastUsed: "0", // refund 1024 (extra used) + 1024 (extra reserved) } var rpl string if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } - eAcntVal = 49999897600.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 89088.000000 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } + if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Received reply: %s", reply) + } + time.Sleep(time.Duration(10) * time.Millisecond) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + Accounts: []string{acntAttrs.Account}} + if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if cdrs[0].Usage != "13312" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } } func TestSMGDataDerivedChargingNoCredit(t *testing.T) { diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index b1f6ef79a..a4b74683b 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -240,7 +240,7 @@ func (self *SMGSession) storeSMCost() error { RunID: self.RunID, OriginHost: self.EventStart.GetOriginatorIP(utils.META_DEFAULT), OriginID: self.EventStart.GetOriginID(utils.META_DEFAULT), - Usage: self.TotalUsage.Seconds(), + Usage: self.TotalUsage, CostDetails: self.EventCost, } var reply string diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 6585aa841..c05732b1c 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -534,7 +534,8 @@ func (smg *SMGeneric) setPassiveSessions(cgrID string, ss []*SMGSession) (err er if len(ss) == 0 { return } - for _, cacheKey := range []string{"InitiateSession" + cgrID, "UpdateSession" + cgrID, "TerminateSession" + cgrID} { + for _, cacheKey := range []string{"InitiateSession" + cgrID, + "UpdateSession" + cgrID, "TerminateSession" + cgrID} { if _, err := smg.responseCache.Get(cacheKey); err == nil { // Stop processing passive when there has been an update over active RPC smg.deletePassiveSessions(cgrID) return ErrActiveSession @@ -965,7 +966,8 @@ func (smg *SMGeneric) ProcessCDR(gev SMGenericEvent) (err error) { } defer smg.responseCache.Cache(cacheKey, &cache.CacheItem{Err: err}) var reply string - if err = smg.cdrsrv.Call("CdrsV1.ProcessCDR", gev.AsStoredCdr(smg.cgrCfg, smg.Timezone), &reply); err != nil { + if err = smg.cdrsrv.Call("CdrsV1.ProcessCDR", + gev.AsStoredCdr(smg.cgrCfg, smg.Timezone), &reply); err != nil { return } return diff --git a/sessionmanager/smgreplc_it_test.go b/sessionmanager/smgreplc_it_test.go index 5ef422848..21c664d37 100644 --- a/sessionmanager/smgreplc_it_test.go +++ b/sessionmanager/smgreplc_it_test.go @@ -110,7 +110,7 @@ func TestSMGRplcInitiate(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1m30s", } - var maxUsage float64 + var maxUsage time.Duration if err := smgRplcMstrRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err == nil && err.Error() != rpcclient.ErrSessionNotFound.Error() { // Update should return rpcclient.ErrSessionNotFound @@ -123,7 +123,7 @@ func TestSMGRplcInitiate(t *testing.T) { if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 90 { + if maxUsage != time.Duration(90*time.Second) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Wait for the sessions to be populated @@ -151,11 +151,11 @@ func TestSMGRplcUpdate(t *testing.T) { utils.ACCID: "123451", utils.USAGE: "1m", } - var maxUsage float64 + var maxUsage time.Duration if err := smgRplcSlvRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 60 { + } else if maxUsage != time.Duration(time.Minute) { t.Error("Bad max usage: ", maxUsage) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Wait for the sessions to be populated @@ -256,11 +256,11 @@ func TestSMGRplcManualReplicate(t *testing.T) { utils.USAGE: "1m30s", } for _, smgEv := range []SMGenericEvent{smgEv1, smgEv2} { - var maxUsage float64 + var maxUsage time.Duration if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 90 { + if maxUsage != time.Duration(90*time.Second) { t.Error("Bad max usage: ", maxUsage) } } diff --git a/utils/coreutils.go b/utils/coreutils.go index 361cb2540..eef7f5b65 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -304,10 +304,15 @@ func MinDuration(d1, d2 time.Duration) time.Duration { // ParseZeroRatingSubject will parse the subject in the balance // returns duration if able to extract it from subject // returns error if not able to parse duration (ie: if ratingSubject is standard one) -func ParseZeroRatingSubject(rateSubj string) (time.Duration, error) { +func ParseZeroRatingSubject(tor, rateSubj string) (time.Duration, error) { rateSubj = strings.TrimSpace(rateSubj) if rateSubj == "" || rateSubj == ANY { - rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s" + switch tor { + case VOICE: + rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s" + default: + rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1ns" + } } if !strings.HasPrefix(rateSubj, ZERO_RATING_SUBJECT_PREFIX) { return 0, errors.New("malformed rating subject: " + rateSubj) diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index b1173425a..deb86cbd6 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -391,7 +391,7 @@ func TestParseZeroRatingSubject(t *testing.T) { subj := []string{"", "*zero1s", "*zero5m", "*zero10h"} dur := []time.Duration{time.Second, time.Second, 5 * time.Minute, 10 * time.Hour} for i, s := range subj { - if d, err := ParseZeroRatingSubject(s); err != nil || d != dur[i] { + if d, err := ParseZeroRatingSubject(VOICE, s); err != nil || d != dur[i] { t.Error("Error parsing rating subject: ", s, d, err) } } From 6e69c0bc9cd7fe1c57933d15f074b3aca6755e07 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 10 Nov 2017 11:43:46 +0100 Subject: [PATCH 19/75] SMG data integration tests --- data/conf/samples/smg/cgrates.json | 2 +- sessionmanager/data_it_test.go | 634 +++++++++-------------------- sessionmanager/smg_event.go | 13 +- sessionmanager/smg_it_test.go | 44 +- sessionmanager/smgeneric.go | 7 +- 5 files changed, 252 insertions(+), 448 deletions(-) diff --git a/data/conf/samples/smg/cgrates.json b/data/conf/samples/smg/cgrates.json index 255f4a2c0..cb8f2a850 100644 --- a/data/conf/samples/smg/cgrates.json +++ b/data/conf/samples/smg/cgrates.json @@ -32,7 +32,7 @@ "sm_generic": { "enabled": true, - //"session_ttl": "50ms", + "session_ttl": "50ms", "rals_conns": [ {"address": "127.0.0.1:2012", "transport": "*json"} ] diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index 7020ab504..c9abff8a6 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -388,7 +388,7 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { } else if reply != utils.OK { t.Errorf("Received reply: %s", reply) } - time.Sleep(time.Duration(10) * time.Millisecond) + time.Sleep(time.Duration(20) * time.Millisecond) var cdrs []*engine.ExternalCDR req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{acntAttrs.Account}} @@ -403,563 +403,319 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { } } -func TestSMGDataDerivedChargingNoCredit(t *testing.T) { - var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1011"} - eAcntVal := 50000.0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) - } - smgEv := SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.VOICE, - utils.ACCID: "1234967", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1011", - utils.SUBJECT: "1011", - utils.DESTINATION: "+49", - utils.CATEGORY: "call", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.SETUP_TIME: "2016-01-05 18:30:49", - utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "100", - } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - // the second derived charging run has no credit - - if maxUsage != 0 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 50000.0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) - } -} - func TestSMGDataTTLExpired(t *testing.T) { var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 49999897600.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + acntAttrs := &utils.AttrGetAccount{Tenant: "cgrates.org", + Account: "TestSMGDataTTLExpired"} + eAcntVal := 102400.0 + attrSetBalance := utils.AttrSetBalance{ + Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, + BalanceType: utils.DATA, + BalanceID: utils.StringPointer("TestSMGDataTTLExpired"), + Value: utils.Float64Pointer(eAcntVal)} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } smgEv := SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123494", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.SETUP_TIME: "2016-01-05 18:30:52", - utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "TestSMGDataTTLExpired", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:52", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "1024", + utils.SessionTTLUsage: "2048", // will be charged on TTL } var maxUsage float64 if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 1024 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998842880.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 101376.000000 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } - time.Sleep(50 * time.Millisecond) - eAcntVal = 49998842880.000000 //1054720 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + time.Sleep(70 * time.Millisecond) + eAcntVal = 99328.000000 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } } -func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) { +func TestSMGDataTTLExpMultiUpdates(t *testing.T) { var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 49998842880.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + acntAttrs := &utils.AttrGetAccount{Tenant: "cgrates.org", + Account: "TestSMGDataTTLExpMultiUpdates"} + eAcntVal := 102400.0 + attrSetBalance := utils.AttrSetBalance{ + Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, + BalanceType: utils.DATA, + BalanceID: utils.StringPointer("TestSMGDataTTLExpMultiUpdates"), + Value: utils.Float64Pointer(eAcntVal)} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } smgEv := SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123495", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, utils.SETUP_TIME: "2016-01-05 18:30:53", utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", + utils.USAGE: "4096", // 3MB } - var maxUsage float64 + var maxUsage int64 if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 4096 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49997788160.000000 //1054720 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 98304.000000 //96MB + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + int64(aSessions[0].Usage) != 4096 { + t.Errorf("wrong active sessions: %d", int64(aSessions[0].Usage)) } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123495", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", - } + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123495", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:53", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.LastUsed: "1024", + utils.USAGE: "4096", + utils.SessionTTLUsage: "2048", // will be charged on TTL + utils.SessionTTLLastUsed: "1024"} // will force last usage on timeout if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 4096 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49997767680.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 97280.000000 // 20480 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) } - - time.Sleep(50 * time.Millisecond) - eAcntVal = 49997767680.000000 //0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + time.Sleep(60 * time.Millisecond) // TTL will kick in + eAcntVal = 98304.000000 // 1MB is returned + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } } func TestSMGDataMultipleDataNoUsage(t *testing.T) { var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 49997767680.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + acntAttrs := &utils.AttrGetAccount{Tenant: "cgrates.org", + Account: "TestSMGDataTTLExpMultiUpdates"} + eAcntVal := 102400.0 + attrSetBalance := utils.AttrSetBalance{ + Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, + BalanceType: utils.DATA, + BalanceID: utils.StringPointer("TestSMGDataTTLExpMultiUpdates"), + Value: utils.Float64Pointer(eAcntVal)} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } smgEv := SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, - utils.ACCID: "123496", + utils.ACCID: "123495", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, - utils.SETUP_TIME: "2016-01-05 18:30:54", + utils.SETUP_TIME: "2016-01-05 18:30:53", utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", + utils.USAGE: "2048", } - var maxUsage float64 + var maxUsage int64 if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 2048 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49996712960.000000 // 1054720 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 100352.000000 // 1054720 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + int64(aSessions[0].Usage) != 2048 { + t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, - utils.ACCID: "123496", + utils.ACCID: "123495", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", + utils.SETUP_TIME: "2016-01-05 18:30:53", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.SessionTTL: "1h", // cancel timeout since usage 0 will not update it + utils.USAGE: "1024", + utils.LastUsed: "1024", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1024 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 100352.000000 // 1054720 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) + } + aSessions = make([]*ActiveSession, 0) + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || + int64(aSessions[0].Usage) != 2048 { + t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) + } + + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123495", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:53", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.SessionTTL: "1h", // cancel timeout since usage 0 will not update it + utils.USAGE: "0", utils.LastUsed: "0", } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 0 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 100352.000000 // 1054720 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) } + aSessions = make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + int64(aSessions[0].Usage) != 1024 { + t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, - utils.ACCID: "123496", + utils.ACCID: "123495", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "0", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123496", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "0", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123496", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "0", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123496", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", utils.TENANT: "cgrates.org", utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:53", + utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.LastUsed: "0", } var rpl string if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } - eAcntVal = 49997767680.000000 // refunded - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 101376.000000 // refunded last 1MB reserved and unused + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } } - -func TestSMGDataMultipleDataConstantUsage(t *testing.T) { - var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"} - eAcntVal := 49997767680.000000 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - smgEv := SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.SETUP_TIME: "2016-01-05 18:30:55", - utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1048576", - } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 1054720 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - aSessions := make([]*ActiveSession, 0) - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049176 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049776 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050376 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050976 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.LastUsed: "0", - } - var rpl string - if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { - t.Error(err) - } - eAcntVal = 49997757440.000000 // 10240 (from the start) - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } -} diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 97e047956..60f2447a5 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -187,19 +187,22 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) } // GetSessionTTL retrieves SessionTTL setting out of SMGenericEvent -func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxDelay *time.Duration) time.Duration { +func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, + cfgSessionTTLMaxDelay *time.Duration) time.Duration { valIf, hasVal := self[utils.SessionTTL] if hasVal { ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { - utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTL, disabling functionality for event: <%s>", - self.GetCGRID(utils.META_DEFAULT))) + utils.Logger.Warning( + fmt.Sprintf("SMGenericEvent, cannot convert SessionTTL, disabling functionality for event: <%s>", + self.GetCGRID(utils.META_DEFAULT))) return time.Duration(0) } var err error 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))) + utils.Logger.Warning( + fmt.Sprintf("SMGenericEvent, cannot parse SessionTTL, disabling functionality for event: <%s>", + self.GetCGRID(utils.META_DEFAULT))) return time.Duration(0) } } diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index 7b1cc4097..bb5f1800c 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -937,9 +937,51 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } } - } +/* +func TestSMGDataDerivedChargingNoCredit(t *testing.T) { + var acnt *engine.Account + attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1011"} + eAcntVal := 50000.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + smgEv := SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.VOICE, + utils.ACCID: "1234967", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1011", + utils.SUBJECT: "1011", + utils.DESTINATION: "+49", + utils.CATEGORY: "call", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:49", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "100", + } + var maxUsage float64 + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + // the second derived charging run has no credit + + if maxUsage != 0 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 50000.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } +} +*/ + // ToDo: Add test for ChargeEvent with derived charging, one with debit possible and second not so we see refund and error.CreditInsufficient showing up. func TestSMGVoiceSessionStopCgrEngine(t *testing.T) { diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index c05732b1c..a6608b5c4 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -747,7 +747,9 @@ func (smg *SMGeneric) UpdateSession(gev SMGenericEvent, clnt rpcclient.RpcClient smg.replicateSessionsWithID(initialCGRID, false, smg.smgReplConns) } smg.resetTerminatorTimer(cgrID, - gev.GetSessionTTL(smg.cgrCfg.SmGenericConfig.SessionTTL, smg.cgrCfg.SmGenericConfig.SessionTTLMaxDelay), + gev.GetSessionTTL( + smg.cgrCfg.SmGenericConfig.SessionTTL, + smg.cgrCfg.SmGenericConfig.SessionTTLMaxDelay), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) var lastUsed *time.Duration var evLastUsed time.Duration @@ -756,7 +758,8 @@ func (smg *SMGeneric) UpdateSession(gev SMGenericEvent, clnt rpcclient.RpcClient } else if err != utils.ErrNotFound { return } - if maxUsage, err = gev.GetMaxUsage(utils.META_DEFAULT, smg.cgrCfg.SmGenericConfig.MaxCallDuration); err != nil { + if maxUsage, err = gev.GetMaxUsage(utils.META_DEFAULT, + smg.cgrCfg.SmGenericConfig.MaxCallDuration); err != nil { if err == utils.ErrNotFound { err = utils.ErrMandatoryIeMissing } From 3c6a8d52b6c00d67597b667fac2586e9a771e827 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 10 Nov 2017 12:26:37 +0100 Subject: [PATCH 20/75] Adding maxComputedUsage tests for data sessions --- data/conf/samples/smg/cgrates.json | 6 +++ sessionmanager/data_it_test.go | 65 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/data/conf/samples/smg/cgrates.json b/data/conf/samples/smg/cgrates.json index cb8f2a850..1d3ab8913 100644 --- a/data/conf/samples/smg/cgrates.json +++ b/data/conf/samples/smg/cgrates.json @@ -20,6 +20,12 @@ "rals": { "enabled": true, // enable Rater service: + "max_computed_usage": { // do not compute usage higher than this, prevents memory overload + "*any": "189h", + "*voice": "72h", + "*data": "102400", + "*sms": "10000" + }, }, "scheduler": { diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index c9abff8a6..41c8ebe76 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -719,3 +719,68 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { t.Error(err, aSessions) } } + +// TestSMGDataTTLUsageProtection makes sure that original TTL (50ms) +// limits the additional debit without overloading memory +func TestSMGDataTTLUsageProtection(t *testing.T) { + var acnt *engine.Account + acntAttrs := &utils.AttrGetAccount{Tenant: "cgrates.org", + Account: "TestSMGDataTTLUsageProtection"} + eAcntVal := 102400.0 + attrSetBalance := utils.AttrSetBalance{ + Tenant: acntAttrs.Tenant, Account: acntAttrs.Account, + BalanceType: utils.DATA, + BalanceID: utils.StringPointer("TestSMGDataTTLUsageProtection"), + Value: utils.Float64Pointer(eAcntVal)} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) + } + smgEv := SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123495", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:53", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "2048", + } + var maxUsage int64 + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 2048 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 100352.000000 // 1054720 + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { + t.Error(err) + } else if dataVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); dataVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, dataVal) + } + aSessions := make([]*ActiveSession, 0) + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || + int64(aSessions[0].Usage) != 2048 { + t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) + } + time.Sleep(60 * time.Millisecond) + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", + nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err, aSessions) + } +} From e0cdcba030f5a4f9102b60c0516e66d511969a3f Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 12 Nov 2017 19:26:07 +0100 Subject: [PATCH 21/75] *voice balance format change into nanoseconds from seconds, some test fixes --- apier/v2/apier.go | 2 +- engine/account.go | 4 +-- engine/balances.go | 2 +- engine/eventcost.go | 1 - engine/tp_reader.go | 6 ++-- general_tests/ddazmbl1_test.go | 62 ++++++++++++++++++++-------------- utils/value_formula.go | 9 +++-- utils/value_formula_test.go | 22 ++++++++++++ 8 files changed, 71 insertions(+), 37 deletions(-) diff --git a/apier/v2/apier.go b/apier/v2/apier.go index cd455dbc8..754adb1cf 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -336,7 +336,7 @@ func (self *ApierV2) SetActions(attrs utils.AttrSetActions, reply *string) error for idx, apiAct := range attrs.Actions { var vf *utils.ValueFormula if apiAct.Units != "" { - if x, err := utils.ParseBalanceFilterValue(apiAct.Units); err == nil { + if x, err := utils.ParseBalanceFilterValue(apiAct.BalanceType, apiAct.Units); err == nil { vf = x } else { return err diff --git a/engine/account.go b/engine/account.go index c6f225b51..bcaeca80b 100644 --- a/engine/account.go +++ b/engine/account.go @@ -393,7 +393,6 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulUnitBalances { //utils.Logger.Info(fmt.Sprintf("Unit balance: %+v", balance)) //utils.Logger.Info(fmt.Sprintf("CD BEFORE UNIT: %+v", cd)) - partCC, debitErr := balance.debitUnits(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { @@ -441,7 +440,8 @@ func (ub *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun boo for _, balance := range usefulMoneyBalances { //utils.Logger.Info(fmt.Sprintf("Money balance: %+v", balance)) //utils.Logger.Info(fmt.Sprintf("CD BEFORE MONEY: %+v", cd)) - partCC, debitErr := balance.debitMoney(cd, balance.account, usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) + partCC, debitErr := balance.debitMoney(cd, balance.account, + usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0) if debitErr != nil { return nil, debitErr } diff --git a/engine/balances.go b/engine/balances.go index b445eba7c..84a1c35f5 100644 --- a/engine/balances.go +++ b/engine/balances.go @@ -517,7 +517,7 @@ func (b *Balance) debitUnits(cd *CallDescriptor, ub *Account, moneyBalances Bala } } else { inc.paid = false - // delete the rest of the unpiad increments/timespans + // delete the rest of the unpaid increments/timespans if incIndex == 0 { // cut the entire current timespan cc.Timespans = cc.Timespans[:tsIndex] diff --git a/engine/eventcost.go b/engine/eventcost.go index 84f9cdf4e..55325274c 100644 --- a/engine/eventcost.go +++ b/engine/eventcost.go @@ -265,7 +265,6 @@ func (ec *EventCost) AsCallCost() *CallCost { ts.TimeEnd = ts.TimeStart.Add( time.Duration(cIl.Usage().Nanoseconds() * int64(cIl.CompressFactor))) if cIl.RatingID != "" { - //fmt.Printf("Checking RatingID: <%s>\n", cIl.RatingID) if ec.Rating[cIl.RatingID].RatingFiltersID != "" { rfs := ec.RatingFilters[ec.Rating[cIl.RatingID].RatingFiltersID] ts.MatchedSubject = rfs["Subject"].(string) diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 4ac0f1ab2..26b264004 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -594,7 +594,7 @@ func (tpr *TpReader) LoadActions() (err error) { } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } @@ -1056,7 +1056,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *utils.TPAccountActions) } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } @@ -1399,7 +1399,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { } if tpact.Units != "" && tpact.Units != utils.ANY { - vf, err := utils.ParseBalanceFilterValue(tpact.Units) + vf, err := utils.ParseBalanceFilterValue(tpact.BalanceType, tpact.Units) if err != nil { return err } diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index 01935f450..096139b6f 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -29,13 +29,13 @@ import ( var dataDB *engine.DataManager -func TestSetStorage(t *testing.T) { +func TestDZ1SetStorage(t *testing.T) { data, _ := engine.NewMapStorageJson() dataDB = engine.NewDataManager(data) engine.SetDataStorage(dataDB) } -func TestLoadCsvTp(t *testing.T) { +func TestDZ1LoadCsvTp(t *testing.T) { timings := `ALWAYS,*any,*any,*any,*any,00:00:00 ASAP,*any,*any,*any,*any,*asap` destinations := `DST_UK_Mobile_BIG5,447596 @@ -51,7 +51,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` sharedGroups := `` lcrs := `` actions := `TOPUP10_AC,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,10,10,false,false,10 -TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,false,false,10` +TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40000000000,10,false,false,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10 TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` @@ -64,8 +64,12 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` - csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + csvr := engine.NewTpReader(dataDB.DataDB(), + engine.NewStringCSVStorage(',', destinations, timings, rates, + destinationRates, ratingPlans, ratingProfiles, + sharedGroups, lcrs, actions, actionPlans, actionTriggers, + accountActions, derivedCharges, cdrStats, users, aliases, + resLimits, stats, thresholds, filters), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -112,37 +116,41 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + /* + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { - t.Error("Wrong number of cached destinations found", cachedDests) - } - if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 2 { - t.Error("Wrong number of cached rating plans found", cachedRPlans) - } - if cachedRProfiles := cache.CountEntries(utils.RATING_PROFILE_PREFIX); cachedRProfiles != 0 { - t.Error("Wrong number of cached rating profiles found", cachedRProfiles) - } - if cachedActions := cache.CountEntries(utils.ACTION_PREFIX); cachedActions != 0 { - t.Error("Wrong number of cached actions found", cachedActions) - } + if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { + t.Error("Wrong number of cached destinations found", cachedDests) + } + if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 2 { + t.Error("Wrong number of cached rating plans found", cachedRPlans) + } + if cachedRProfiles := cache.CountEntries(utils.RATING_PROFILE_PREFIX); cachedRProfiles != 0 { + t.Error("Wrong number of cached rating profiles found", cachedRProfiles) + } + if cachedActions := cache.CountEntries(utils.ACTION_PREFIX); cachedActions != 0 { + t.Error("Wrong number of cached actions found", cachedActions) + } + */ } -func TestExecuteActions(t *testing.T) { +func TestDZ1ExecuteActions(t *testing.T) { scheduler.NewScheduler(dataDB).Reload() time.Sleep(10 * time.Millisecond) // Give time to scheduler to topup the account if acnt, err := dataDB.DataDB().GetAccount("cgrates.org:12344"); err != nil { t.Error(err) } else if len(acnt.BalanceMap) != 2 { t.Error("Account does not have enough balances: ", acnt.BalanceMap) - } else if acnt.BalanceMap[utils.VOICE][0].Value != 40 { - t.Error("Account does not have enough minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) + } else if acnt.BalanceMap[utils.VOICE][0].Value != 40000000000 { + t.Error("Account does not have enough minutes in balance", + acnt.BalanceMap[utils.VOICE][0].Value) } else if acnt.BalanceMap[utils.MONETARY][0].Value != 10 { - t.Error("Account does not have enough monetary balance", acnt.BalanceMap[utils.MONETARY][0].Value) + t.Error("Account does not have enough monetary balance", + acnt.BalanceMap[utils.MONETARY][0].Value) } } -func TestDebit(t *testing.T) { +func TestDZ1Debit(t *testing.T) { cd := &engine.CallDescriptor{ Direction: "*out", Category: "call", @@ -162,10 +170,12 @@ func TestDebit(t *testing.T) { if err != nil { t.Error(err) } - if acnt.BalanceMap[utils.VOICE][0].Value != 20 { - t.Error("Account does not have expected minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) + if acnt.BalanceMap[utils.VOICE][0].Value != 20000000000 { + t.Error("Account does not have expected *voice units in balance", + acnt.BalanceMap[utils.VOICE][0].Value) } if acnt.BalanceMap[utils.MONETARY][0].Value != 9.99 { - t.Error("Account does not have expected monetary balance", acnt.BalanceMap[utils.MONETARY][0].Value) + t.Error("Account does not have expected *monetary units in balance", + acnt.BalanceMap[utils.MONETARY][0].Value) } } diff --git a/utils/value_formula.go b/utils/value_formula.go index 4c292a108..9ee2217e7 100644 --- a/utils/value_formula.go +++ b/utils/value_formula.go @@ -33,9 +33,12 @@ type ValueFormula struct { Static float64 } -func ParseBalanceFilterValue(val string) (*ValueFormula, error) { - u, err := strconv.ParseFloat(val, 64) - if err == nil { +func ParseBalanceFilterValue(tor string, val string) (*ValueFormula, error) { + if tor == VOICE { // VOICE balance is parsed as nanoseconds with support for time duration strings + if d, err := ParseDurationWithNanosecs(val); err == nil { + return &ValueFormula{Static: float64(d.Nanoseconds())}, err + } + } else if u, err := strconv.ParseFloat(val, 64); err == nil { return &ValueFormula{Static: u}, err } var vf ValueFormula diff --git a/utils/value_formula_test.go b/utils/value_formula_test.go index 3a42ee9b0..2f3da0086 100644 --- a/utils/value_formula_test.go +++ b/utils/value_formula_test.go @@ -19,6 +19,7 @@ package utils import ( "encoding/json" + "reflect" "testing" "time" ) @@ -54,3 +55,24 @@ func TestValueFormulaDayYear(t *testing.T) { t.Error("error caclulating value using formula: ", x) } } + +func TestValueFormulaParseBalanceFilterValue(t *testing.T) { + eVF := &ValueFormula{Static: 10000000000.0} + if vf, err := ParseBalanceFilterValue(VOICE, "10s"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } + eVF = &ValueFormula{Static: 1024.0} + if vf, err := ParseBalanceFilterValue(DATA, "1024"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } + eVF = &ValueFormula{Static: 10.0} + if vf, err := ParseBalanceFilterValue(MONETARY, "10"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eVF, vf) { + t.Errorf("Expecting: %+v, received: %+v", eVF, vf) + } +} From 26b95954c2a046c3e2529a097729b7c6bd37f81a Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 6 Nov 2017 16:39:26 +0200 Subject: [PATCH 22/75] Show number of Timespans in a1_it_test.go on line 220 --- general_tests/a1_it_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index 79eb14306..cd9ca0110 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -218,7 +218,7 @@ func TestA1itDataSession1(t *testing.T) { t.Error(err) } if len(cc.Timespans) != 3 { - t.Errorf("Unexpected number of timespans: %+v", cc.Timespans) + t.Errorf("Unexpected number of timespans: %+v", len(cc.Timespans)) } if cc.RatedUsage != 2202800 { t.Errorf("RatingUsage expected: %f received %f, callcost: %+v ", 2202800.0, cc.RatedUsage, cc) From c37015a09ca8f82a002c3705992a6ae43440ff8d Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 13 Nov 2017 14:02:07 +0200 Subject: [PATCH 23/75] Remove AccountSummary from config.cdrs --- config/config.go | 3 --- config/config_defaults.go | 1 - config/config_json_test.go | 9 ++++----- config/libconfig_json.go | 25 ++++++++++++------------- data/conf/cgrates/cgrates.json | 1 - general_tests/tutorial_it_test.go | 2 +- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/config/config.go b/config/config.go index 67469ece0..59622dfa2 100755 --- a/config/config.go +++ b/config/config.go @@ -942,9 +942,6 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnCdrsCfg.Store_cdrs != nil { self.CDRSStoreCdrs = *jsnCdrsCfg.Store_cdrs } - if jsnCdrsCfg.Cdr_account_summary != nil { - self.CDRScdrAccountSummary = *jsnCdrsCfg.Cdr_account_summary - } if jsnCdrsCfg.Sm_cost_retries != nil { self.CDRSSMCostRetries = *jsnCdrsCfg.Sm_cost_retries } diff --git a/config/config_defaults.go b/config/config_defaults.go index d0a2dc4f7..e7d2a4d8c 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -152,7 +152,6 @@ const CGRATES_CFG_JSON = ` "enabled": false, // start the CDR Server service: "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs "store_cdrs": true, // store cdrs in storDb - "cdr_account_summary": false, // add account information from dataDB "sm_cost_retries": 5, // number of queries to sm_costs before recalculating CDR "rals_conns": [ {"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234> diff --git a/config/config_json_test.go b/config/config_json_test.go index 3f523547b..7ec072018 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -230,11 +230,10 @@ func TestDfSchedulerJsonCfg(t *testing.T) { func TestDfCdrsJsonCfg(t *testing.T) { eCfg := &CdrsJsonCfg{ - Enabled: utils.BoolPointer(false), - Extra_fields: utils.StringSlicePointer([]string{}), - Store_cdrs: utils.BoolPointer(true), - Cdr_account_summary: utils.BoolPointer(false), - Sm_cost_retries: utils.IntPointer(5), + Enabled: utils.BoolPointer(false), + Extra_fields: utils.StringSlicePointer([]string{}), + Store_cdrs: utils.BoolPointer(true), + Sm_cost_retries: utils.IntPointer(5), Rals_conns: &[]*HaPoolJsonCfg{ &HaPoolJsonCfg{ Address: utils.StringPointer("*internal"), diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 42ff3ff64..ec9046d5a 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -99,19 +99,18 @@ type SchedulerJsonCfg struct { // Cdrs config section type CdrsJsonCfg struct { - Enabled *bool - Extra_fields *[]string - Store_cdrs *bool - Cdr_account_summary *bool - Sm_cost_retries *int - Rals_conns *[]*HaPoolJsonCfg - Pubsubs_conns *[]*HaPoolJsonCfg - Users_conns *[]*HaPoolJsonCfg - Aliases_conns *[]*HaPoolJsonCfg - Cdrstats_conns *[]*HaPoolJsonCfg - Thresholds_conns *[]*HaPoolJsonCfg - Stats_conns *[]*HaPoolJsonCfg - Online_cdr_exports *[]string + Enabled *bool + Extra_fields *[]string + Store_cdrs *bool + Sm_cost_retries *int + Rals_conns *[]*HaPoolJsonCfg + Pubsubs_conns *[]*HaPoolJsonCfg + Users_conns *[]*HaPoolJsonCfg + Aliases_conns *[]*HaPoolJsonCfg + Cdrstats_conns *[]*HaPoolJsonCfg + Thresholds_conns *[]*HaPoolJsonCfg + Stats_conns *[]*HaPoolJsonCfg + Online_cdr_exports *[]string } type CdrReplicationJsonCfg struct { diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index 797245dd1..a5e3f3d95 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -110,7 +110,6 @@ // "enabled": false, // start the CDR Server service: // "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs // "store_cdrs": true, // store cdrs in storDb -// "cdr_account_summary": false, // add account information from dataDB // "sm_cost_retries": 5, // number of queries to sm_costs before recalculating CDR // "rals_conns": [ // {"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234> diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index 84328c3ba..e93e367b4 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -1332,7 +1332,7 @@ func TestTutITPrepaidCDRWithSMCost(t *testing.T) { OriginHost: cdr.OriginHost, OriginID: cdr.OriginID, CostSource: "TestTutITPrepaidCDRWithSMCost", - Usage: cdr.Usage.Seconds(), + Usage: cdr.Usage, CostDetails: &engine.CallCost{ Direction: utils.OUT, Destination: "1003", From 4ecf972f40d8799bc535b1ef01294930e98946c8 Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 13 Nov 2017 15:40:44 +0200 Subject: [PATCH 24/75] Add test for AsCDRsql and NewCDRFromSQL --- engine/cdr_test.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/engine/cdr_test.go b/engine/cdr_test.go index a94ee168b..48ae792e9 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -685,3 +685,102 @@ func TestCDRAsExportMap(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eCDRMp, cdrMp) } } + +func TestCDRAsCDRsql(t *testing.T) { + 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: utils.UNIT_TEST, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "+4986517174963", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).Local(), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Local(), + RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(10) * time.Second, + Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + } + eCDR := cdr.AsCDRsql() + eCDRSql := &CDRsql{ + Cgrid: cdr.CGRID, + RunID: cdr.RunID, + OriginID: "dsafdsaf", + TOR: utils.VOICE, + Source: utils.UNIT_TEST, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "+4986517174963", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).Local(), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Local(), + Usage: cdr.Usage.Nanoseconds(), + Cost: cdr.Cost, + ExtraFields: utils.ToJSON(cdr.ExtraFields), + RequestType: cdr.RequestType, + OriginHost: cdr.OriginHost, + CostDetails: utils.ToJSON(cdr.CostDetails), + CreatedAt: eCDR.CreatedAt, + } + if !reflect.DeepEqual(eCDR, eCDRSql) { + t.Errorf("Expecting: %+v, received: %+v", eCDR, eCDRSql) + } + +} + +func TestCDRNewCDRFromSQL(t *testing.T) { + extraFields := map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"} + cdrSql := &CDRsql{ + ID: 123, + Cgrid: "abecd993d06672714c4218a6dcf8278e0589a171", + RunID: "*default", + OriginID: "dsafdsaf", + TOR: utils.VOICE, + Source: utils.UNIT_TEST, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "+4986517174963", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).Local(), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Local(), + Usage: 10000000000, + Cost: 1.01, + RequestType: utils.META_RATED, + OriginHost: "192.168.1.1", + ExtraFields: utils.ToJSON(extraFields), + } + + 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: utils.UNIT_TEST, + RequestType: utils.META_RATED, + Tenant: "cgrates.org", + Category: "call", + Account: "1001", + Subject: "1001", + Destination: "+4986517174963", + SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).Local(), + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).Local(), + RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(10) * time.Second, + Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + } + + if eCDR, err := NewCDRFromSQL(cdrSql); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(cdr, eCDR) { + t.Errorf("Expecting: %+v, received: %+v", cdr, eCDR) + } + +} From d081229d0d66ae506f5ec4b2a9e950e0acfcfc2f Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 17 Nov 2017 14:26:08 +0100 Subject: [PATCH 25/75] Build test fixes --- engine/account_test.go | 425 +++++++++++++++++++++++++-------- engine/callcost_test.go | 6 +- engine/calldesc_test.go | 91 ++++--- engine/loader_csv_test.go | 12 +- engine/rateinterval.go | 2 +- engine/responder_test.go | 30 ++- general_tests/ddazmbl2_test.go | 6 +- general_tests/ddazmbl3_test.go | 6 +- 8 files changed, 419 insertions(+), 159 deletions(-) diff --git a/engine/account_test.go b/engine/account_test.go index eda9563e2..a97e04c98 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -31,7 +31,8 @@ var ( ) func TestBalanceStoreRestore(t *testing.T) { - b := &Balance{Value: 14, Weight: 1, Uuid: "test", ExpirationDate: time.Date(2013, time.July, 15, 17, 48, 0, 0, time.UTC)} + b := &Balance{Value: 14, Weight: 1, Uuid: "test", + ExpirationDate: time.Date(2013, time.July, 15, 17, 48, 0, 0, time.UTC)} marsh := NewCodecMsgpackMarshaler() output, err := marsh.Marshal(b) if err != nil { @@ -154,7 +155,10 @@ func TestAccountStorageStore(t *testing.T) { } b1 := &Balance{Value: 10, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}} b2 := &Balance{Value: 100, Weight: 20, DestinationIDs: utils.StringMap{"RET": true}} - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{utils.VOICE: Balances{b1, b2}, utils.MONETARY: Balances{&Balance{Value: 21}}}} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{b1, b2}, + utils.MONETARY: Balances{&Balance{Value: 21}}}} dm.DataDB().SetAccount(rifsBalance) result, err := dm.DataDB().GetAccount(rifsBalance.ID) if err != nil || rifsBalance.ID != result.ID || @@ -167,7 +171,10 @@ func TestAccountStorageStore(t *testing.T) { } func TestDebitCreditZeroSecond(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1s"} + b1 := &Balance{ + Uuid: "testb", Value: 10 * float64(time.Second), Weight: 10, + DestinationIDs: utils.StringMap{"NAT": true}, + RatingSubject: "*zero1s"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -289,7 +296,9 @@ func TestDebitFreeEmpty(t *testing.T) { } func TestDebitCreditZeroMinute(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70 * float64(time.Second), + Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, + RatingSubject: "*zero1m"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -298,7 +307,11 @@ func TestDebitCreditZeroMinute(t *testing.T) { TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC), DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -312,10 +325,12 @@ func TestDebitCreditZeroMinute(t *testing.T) { TOR: utils.VOICE, testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.VOICE: Balances{b1}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ + ID: "other", + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{b1}, + utils.MONETARY: Balances{&Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { @@ -324,18 +339,23 @@ func TestDebitCreditZeroMinute(t *testing.T) { //t.Logf("%+v", cc.Timespans) if cc.Timespans[0].Increments[0].BalanceInfo.Unit.UUID != "testb" || cc.Timespans[0].Increments[0].Duration != time.Minute { - t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) + t.Errorf("Error setting balance id to increment: %s", + utils.ToJSON(cc)) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10 || + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10*float64(time.Second) || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { - t.Error("Error extracting minutes from balance: ", - rifsBalance.BalanceMap[utils.VOICE][0]) + t.Errorf("Error extracting minutes from balance: %s", + utils.ToJSON(rifsBalance.BalanceMap[utils.VOICE][0])) } } func TestDebitCreditZeroMixedMinute(t *testing.T) { - b1 := &Balance{Uuid: "testm", Value: 70, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} - b2 := &Balance{Uuid: "tests", Value: 10, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1s"} + b1 := &Balance{ + Uuid: "testm", Value: 70 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + RatingSubject: "*zero1m", Weight: 5} + b2 := &Balance{Uuid: "tests", Value: 10 * float64(time.Second), Weight: 10, + DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1s"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -373,7 +393,7 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) { t.Error("Error setting balance id to increment: ", cc.Timespans) } if rifsBalance.BalanceMap[utils.VOICE][1].GetValue() != 0 || - rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10 || + rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10*float64(time.Second) || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { t.Logf("TS0: %+v", cc.Timespans[0]) t.Logf("TS1: %+v", cc.Timespans[1]) @@ -382,7 +402,9 @@ func TestDebitCreditZeroMixedMinute(t *testing.T) { } func TestDebitCreditNoCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + RatingSubject: "*zero1m", Weight: 10} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -391,13 +413,23 @@ func TestDebitCreditNoCredit(t *testing.T) { TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC), DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, &TimeSpan{ TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC), TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC), DurationIndex: 10 * time.Second, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -411,9 +443,10 @@ func TestDebitCreditNoCredit(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.VOICE: Balances{b1}, - }} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{b1}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err == nil { @@ -423,7 +456,7 @@ func TestDebitCreditNoCredit(t *testing.T) { cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10 { + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10*float64(time.Second) { t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.VOICE][0]) } @@ -433,7 +466,9 @@ func TestDebitCreditNoCredit(t *testing.T) { } func TestDebitCreditHasCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 10, RatingSubject: "*zero1m"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -475,10 +510,11 @@ func TestDebitCreditHasCredit(t *testing.T) { cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10 || + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10*float64(time.Second) || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 30 { t.Errorf("Error extracting minutes from balance: %+v, %+v", - rifsBalance.BalanceMap[utils.VOICE][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + rifsBalance.BalanceMap[utils.VOICE][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } if len(cc.Timespans) != 3 || cc.Timespans[0].GetDuration() != time.Minute { t.Error("Error truncating extra timespans: ", cc.Timespans) @@ -486,7 +522,9 @@ func TestDebitCreditHasCredit(t *testing.T) { } func TestDebitCreditSplitMinutesMoney(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testb", Value: 10 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 10, RatingSubject: "*zero1s"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -496,7 +534,12 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) { TimeEnd: time.Date(2013, 9, 24, 10, 48, 20, 0, time.UTC), DurationIndex: 0, ratingInfo: &RatingInfo{}, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 1, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 1, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -534,7 +577,9 @@ func TestDebitCreditSplitMinutesMoney(t *testing.T) { } func TestDebitCreditMoreTimespans(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 150, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 150 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 10, RatingSubject: "*zero1m"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -543,13 +588,22 @@ func TestDebitCreditMoreTimespans(t *testing.T) { TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), TimeEnd: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC), DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, &TimeSpan{ TimeStart: time.Date(2013, 9, 24, 10, 48, 10, 0, time.UTC), TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC), DurationIndex: 10 * time.Second, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 10 * time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -575,15 +629,19 @@ func TestDebitCreditMoreTimespans(t *testing.T) { cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 30 { + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 30*float64(time.Second) { t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.VOICE][0]) } } func TestDebitCreditMoreTimespansMixed(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} - b2 := &Balance{Uuid: "testa", Value: 150, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1s"} + b1 := &Balance{Uuid: "testb", Value: 70 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 10, RatingSubject: "*zero1m"} + b2 := &Balance{Uuid: "testa", Value: 150 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 5, RatingSubject: "*zero1s"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -624,15 +682,17 @@ func TestDebitCreditMoreTimespansMixed(t *testing.T) { cc.Timespans[0].Increments[0].Duration != time.Minute { t.Error("Error setting balance id to increment: ", cc.Timespans[0].Increments[0]) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10 || - rifsBalance.BalanceMap[utils.VOICE][1].GetValue() != 130 { + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 10*float64(time.Second) || + rifsBalance.BalanceMap[utils.VOICE][1].GetValue() != 130*float64(time.Second) { t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.VOICE][1], cc.Timespans[1]) } } func TestDebitCreditNoConectFeeCredit(t *testing.T) { - b1 := &Balance{Uuid: "testb", Value: 70, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "*zero1m"} + b1 := &Balance{Uuid: "testb", Value: 70 * float64(time.Second), + DestinationIDs: utils.StringMap{"NAT": true}, + Weight: 10, RatingSubject: "*zero1m"} cc := &CallCost{ Direction: utils.OUT, Destination: "0723045326", @@ -731,7 +791,11 @@ func TestDebitCreditMoneyOnly(t *testing.T) { } func TestDebitCreditSubjectMinutes(t *testing.T) { - b1 := &Balance{Uuid: "testb", Categories: utils.NewStringMap("0"), Value: 250, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "minu"} + b1 := &Balance{Uuid: "testb", + Categories: utils.NewStringMap("0"), + Value: 250 * float64(time.Second), + Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, + RatingSubject: "minu"} cc := &CallCost{ Tenant: "vdf", Category: "0", @@ -773,10 +837,11 @@ func TestDebitCreditSubjectMinutes(t *testing.T) { cc.Timespans[0].Increments[0].Duration != 10*time.Second { t.Errorf("Error setting balance id to increment: %+v", cc.Timespans[0].Increments[0]) } - if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 180 || + if rifsBalance.BalanceMap[utils.VOICE][0].GetValue() != 180*float64(time.Second) || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 280 { t.Errorf("Error extracting minutes from balance: %+v, %+v", - rifsBalance.BalanceMap[utils.VOICE][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + rifsBalance.BalanceMap[utils.VOICE][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } if len(cc.Timespans) != 1 || cc.Timespans[0].GetDuration() != 70*time.Second { for _, ts := range cc.Timespans { @@ -1004,53 +1069,128 @@ func TestAccountAddMinutBucketEmpty(t *testing.T) { func TestAccountExecuteTriggeredActions(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}}, &Balance{Weight: 10, DestinationIDs: utils.StringMap{"RET": true}}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.StringMap{utils.OUT: true})}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsID: "TEST_ACTIONS"}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{ + &Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, + utils.VOICE: Balances{ + &Balance{Value: 10 * float64(time.Second), + Weight: 20, + DestinationIDs: utils.StringMap{"NAT": true}, + Directions: utils.StringMap{utils.OUT: true}}, + &Balance{Weight: 10, + DestinationIDs: utils.StringMap{"RET": true}}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{ + &CounterFilter{Value: 1, + Filter: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.StringMap{utils.OUT: true})}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + ActionsID: "TEST_ACTIONS"}}, } ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil) - if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { - t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) + if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || + ub.BalanceMap[utils.VOICE][0].GetValue() != 20*float64(time.Second) { + t.Error("Error executing triggered actions", + ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) } // are set to executed ub.countUnits(1, utils.MONETARY, nil, nil) - if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { - t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) + if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || + ub.BalanceMap[utils.VOICE][0].GetValue() != 20*float64(time.Second) { + t.Error("Error executing triggered actions", + ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) } // we can reset them ub.ResetActionTriggers(nil) ub.countUnits(10, utils.MONETARY, nil, nil) - if ub.BalanceMap[utils.MONETARY][0].GetValue() != 120 || ub.BalanceMap[utils.VOICE][0].GetValue() != 30 { - t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue()) + if ub.BalanceMap[utils.MONETARY][0].GetValue() != 120 || + ub.BalanceMap[utils.VOICE][0].GetValue() != 30*float64(time.Second) { + t.Error("Error executing triggered actions", + ub.BalanceMap[utils.MONETARY][0].GetValue(), + ub.BalanceMap[utils.VOICE][0].GetValue()) } } func TestAccountExecuteTriggeredActionsBalance(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 10, Weight: 20, DestinationIDs: utils.StringMap{"NAT": true}}, &Balance{Directions: utils.NewStringMap(utils.OUT), Weight: 10, DestinationIDs: utils.StringMap{"RET": true}}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, Value: 1.0}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ActionsID: "TEST_ACTIONS"}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{ + &Balance{ + Directions: utils.NewStringMap(utils.OUT), + Value: 100}}, + utils.VOICE: Balances{ + &Balance{ + Directions: utils.NewStringMap(utils.OUT), + Value: 10 * float64(time.Second), + Weight: 20, + DestinationIDs: utils.StringMap{"NAT": true}}, + &Balance{ + Directions: utils.NewStringMap(utils.OUT), + Weight: 10, + DestinationIDs: utils.StringMap{"RET": true}}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{ + &CounterFilter{Filter: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + Value: 1.0}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 100, + ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, + ActionsID: "TEST_ACTIONS"}}, } ub.countUnits(1, utils.MONETARY, nil, nil) - if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || ub.BalanceMap[utils.VOICE][0].GetValue() != 20 { - t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue(), len(ub.BalanceMap[utils.MONETARY])) + if ub.BalanceMap[utils.MONETARY][0].GetValue() != 110 || + ub.BalanceMap[utils.VOICE][0].GetValue() != 20*float64(time.Second) { + t.Error("Error executing triggered actions", + ub.BalanceMap[utils.MONETARY][0].GetValue(), + ub.BalanceMap[utils.VOICE][0].GetValue(), + len(ub.BalanceMap[utils.MONETARY])) } } func TestAccountExecuteTriggeredActionsOrder(t *testing.T) { ub := &Account{ - ID: "TEST_UB_OREDER", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}}, - UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Type: utils.StringPointer(utils.MONETARY)}}}}}}, - ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsID: "TEST_ACTIONS_ORDER"}}, + ID: "TEST_UB_OREDER", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{ + &Balance{Directions: utils.NewStringMap(utils.OUT), + Value: 100}}}, + UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{ + &UnitCounter{Counters: CounterFilters{ + &CounterFilter{Value: 1, Filter: &BalanceFilter{ + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + Type: utils.StringPointer(utils.MONETARY)}}}}}}, + ActionTriggers: ActionTriggers{ + &ActionTrigger{Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 2, + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + ActionsID: "TEST_ACTIONS_ORDER"}}, } ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil) - if len(ub.BalanceMap[utils.MONETARY]) != 1 || ub.BalanceMap[utils.MONETARY][0].GetValue() != 10 { + if len(ub.BalanceMap[utils.MONETARY]) != 1 || + ub.BalanceMap[utils.MONETARY][0].GetValue() != 10 { - t.Errorf("Error executing triggered actions in order %v", ub.BalanceMap[utils.MONETARY][0].GetValue()) + t.Errorf("Error executing triggered actions in order %v", + ub.BalanceMap[utils.MONETARY][0].GetValue()) } } @@ -1084,19 +1224,35 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) { func TestAccountExpActionTrigger(t *testing.T) { ub := &Account{ - ID: "TEST_UB", - BalanceMap: map[string]Balances{utils.MONETARY: Balances{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100, ExpirationDate: time.Date(2015, time.November, 9, 9, 48, 0, 0, time.UTC)}}, utils.VOICE: Balances{&Balance{Value: 10, Weight: 20, DestinationIDs: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}}, &Balance{Weight: 10, DestinationIDs: utils.StringMap{"RET": true}}}}, + ID: "TEST_UB", + BalanceMap: map[string]Balances{ + utils.MONETARY: Balances{ + &Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100, + ExpirationDate: time.Date(2015, time.November, 9, 9, 48, 0, 0, time.UTC)}}, + utils.VOICE: Balances{ + &Balance{Value: 10 * float64(time.Second), Weight: 20, + DestinationIDs: utils.StringMap{"NAT": true}, + Directions: utils.StringMap{utils.OUT: true}}, + &Balance{Weight: 10 * float64(time.Second), + DestinationIDs: utils.StringMap{"RET": true}}}}, ActionTriggers: ActionTriggers{ - &ActionTrigger{ID: "check expired balances", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, ActionsID: "TEST_ACTIONS"}, + &ActionTrigger{ID: "check expired balances", Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, + ThresholdValue: 10, ThresholdType: utils.TRIGGER_BALANCE_EXPIRED, + ActionsID: "TEST_ACTIONS"}, }, } ub.ExecuteActionTriggers(nil) if ub.BalanceMap[utils.MONETARY][0].IsExpired() || ub.BalanceMap[utils.MONETARY][0].GetValue() != 10 || // expired was cleaned - ub.BalanceMap[utils.VOICE][0].GetValue() != 20 || + ub.BalanceMap[utils.VOICE][0].GetValue() != 20*float64(time.Second) || ub.ActionTriggers[0].Executed != true { t.Log(ub.BalanceMap[utils.MONETARY][0].IsExpired()) - t.Error("Error executing triggered actions", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.VOICE][0].GetValue(), len(ub.BalanceMap[utils.MONETARY])) + t.Error("Error executing triggered actions", + ub.BalanceMap[utils.MONETARY][0].GetValue(), + ub.BalanceMap[utils.VOICE][0].GetValue(), + len(ub.BalanceMap[utils.MONETARY])) } } @@ -1168,13 +1324,17 @@ func TestCleanExpired(t *testing.T) { } func TestAccountUnitCounting(t *testing.T) { - ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0}}}}}} + ub := &Account{UnitCounters: UnitCounters{ + utils.MONETARY: []*UnitCounter{&UnitCounter{ + Counters: CounterFilters{&CounterFilter{Value: 0}}}}}} ub.countUnits(10, utils.MONETARY, &CallCost{}, nil) - if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 { + if len(ub.UnitCounters[utils.MONETARY]) != 1 || + ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 { t.Error("Error counting units") } ub.countUnits(10, utils.MONETARY, &CallCost{}, nil) - if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 { + if len(ub.UnitCounters[utils.MONETARY]) != 1 || + ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 { t.Error("Error counting units") } } @@ -1362,10 +1522,16 @@ func TestDebitSMS(t *testing.T) { Timespans: []*TimeSpan{ &TimeSpan{ TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 24, 10, 48, 1, 0, time.UTC), + TimeEnd: time.Date(2013, 9, 24, 10, 48, 0, 1, time.UTC), ratingInfo: &RatingInfo{}, DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, + Value: 100, + RateIncrement: 1, + RateUnit: time.Nanosecond}}}}, }, }, TOR: utils.SMS, @@ -1379,10 +1545,15 @@ func TestDebitSMS(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.SMS: Balances{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}}}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.SMS: Balances{ + &Balance{Uuid: "testm", + Value: 100, Weight: 5, + DestinationIDs: utils.StringMap{"NAT": true}}}, + utils.MONETARY: Balances{ + &Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { @@ -1394,7 +1565,9 @@ func TestDebitSMS(t *testing.T) { if rifsBalance.BalanceMap[utils.SMS][0].GetValue() != 99 || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { t.Log(cc.Timespans[0].Increments) - t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.SMS][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + t.Error("Error extracting minutes from balance: ", + rifsBalance.BalanceMap[utils.SMS][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } } @@ -1405,10 +1578,15 @@ func TestDebitGeneric(t *testing.T) { Timespans: []*TimeSpan{ &TimeSpan{ TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 24, 10, 48, 1, 0, time.UTC), + TimeEnd: time.Date(2013, 9, 24, 10, 48, 0, 1, time.UTC), ratingInfo: &RatingInfo{}, DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 100, + RateIncrement: 1, + RateUnit: time.Nanosecond}}}}, }, }, TOR: utils.GENERIC, @@ -1422,10 +1600,13 @@ func TestDebitGeneric(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.GENERIC: Balances{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}}}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.GENERIC: Balances{ + &Balance{Uuid: "testm", Value: 100, Weight: 5, + DestinationIDs: utils.StringMap{"NAT": true}}}, + utils.MONETARY: Balances{&Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { @@ -1451,7 +1632,13 @@ func TestDebitGenericBalance(t *testing.T) { TimeEnd: time.Date(2013, 9, 24, 10, 48, 30, 0, time.UTC), ratingInfo: &RatingInfo{}, DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 1 * time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, + Value: 100, + RateIncrement: 1 * time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -1465,10 +1652,14 @@ func TestDebitGenericBalance(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.GENERIC: Balances{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}, Factor: ValueFactor{utils.VOICE: 60.0}}}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ + ID: "other", BalanceMap: map[string]Balances{ + utils.GENERIC: Balances{ + &Balance{Uuid: "testm", Value: 100, Weight: 5, + DestinationIDs: utils.StringMap{"NAT": true}, + Factor: ValueFactor{utils.VOICE: 60 * float64(time.Second)}}}, + utils.MONETARY: Balances{&Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { @@ -1480,7 +1671,9 @@ func TestDebitGenericBalance(t *testing.T) { if rifsBalance.BalanceMap[utils.GENERIC][0].GetValue() != 99.49999 || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { t.Logf("%+v", cc.Timespans[0].Increments[0]) - t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + t.Error("Error extracting minutes from balance: ", + rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } } @@ -1494,7 +1687,12 @@ func TestDebitGenericBalanceWithRatingSubject(t *testing.T) { TimeEnd: time.Date(2013, 9, 24, 10, 48, 30, 0, time.UTC), ratingInfo: &RatingInfo{}, DurationIndex: 0, - RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 0, RateIncrement: time.Second, RateUnit: time.Second}}}}, + RateInterval: &RateInterval{ + Rating: &RIRate{ + Rates: RateGroups{ + &Rate{GroupIntervalStart: 0, Value: 0, + RateIncrement: time.Second, + RateUnit: time.Second}}}}, }, }, TOR: utils.VOICE, @@ -1508,10 +1706,15 @@ func TestDebitGenericBalanceWithRatingSubject(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.GENERIC: Balances{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}, Factor: ValueFactor{utils.VOICE: 60.0}, RatingSubject: "free"}}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.GENERIC: Balances{ + &Balance{Uuid: "testm", Value: 100, + Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}, + Factor: ValueFactor{utils.VOICE: 60 * float64(time.Second)}, + RatingSubject: "free"}}, + utils.MONETARY: Balances{&Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) if err != nil { @@ -1523,7 +1726,9 @@ func TestDebitGenericBalanceWithRatingSubject(t *testing.T) { if rifsBalance.BalanceMap[utils.GENERIC][0].GetValue() != 99.49999 || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { t.Logf("%+v", cc.Timespans[0].Increments[0]) - t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + t.Error("Error extracting minutes from balance: ", + rifsBalance.BalanceMap[utils.GENERIC][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } } @@ -1534,14 +1739,19 @@ func TestDebitDataUnits(t *testing.T) { Timespans: []*TimeSpan{ &TimeSpan{ TimeStart: time.Date(2013, 9, 24, 10, 48, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 24, 10, 49, 20, 0, time.UTC), + TimeEnd: time.Date(2013, 9, 24, 10, 48, 0, 80, time.UTC), ratingInfo: &RatingInfo{}, DurationIndex: 0, RateInterval: &RateInterval{ Rating: &RIRate{ Rates: RateGroups{ - &Rate{GroupIntervalStart: 0, Value: 2, RateIncrement: 1 * time.Second, RateUnit: time.Minute}, - &Rate{GroupIntervalStart: 60, Value: 1, RateIncrement: 1 * time.Second, RateUnit: time.Second}, + &Rate{GroupIntervalStart: 0, + Value: 2, RateIncrement: 1, + RateUnit: 1}, + &Rate{GroupIntervalStart: 60, + Value: 1, + RateIncrement: 1, + RateUnit: 1}, }, }, }, @@ -1558,15 +1768,20 @@ func TestDebitDataUnits(t *testing.T) { DurationIndex: cc.GetDuration(), testCallcost: cc, } - rifsBalance := &Account{ID: "other", BalanceMap: map[string]Balances{ - utils.DATA: Balances{&Balance{Uuid: "testm", Value: 100, Weight: 5, DestinationIDs: utils.StringMap{"NAT": true}}}, - utils.MONETARY: Balances{&Balance{Value: 21}}, - }} + rifsBalance := &Account{ID: "other", + BalanceMap: map[string]Balances{ + utils.DATA: Balances{ + &Balance{Uuid: "testm", Value: 100, + Weight: 5, + DestinationIDs: utils.StringMap{"NAT": true}}}, + utils.MONETARY: Balances{&Balance{Value: 21}}, + }} var err error cc, err = rifsBalance.debitCreditBalance(cd, false, false, true) // test rating information ts := cc.Timespans[0] - if ts.MatchedSubject != "testm" || ts.MatchedPrefix != "0723" || ts.MatchedDestId != "NAT" || ts.RatingPlanId != utils.META_NONE { + if ts.MatchedSubject != "testm" || ts.MatchedPrefix != "0723" || + ts.MatchedDestId != "NAT" || ts.RatingPlanId != utils.META_NONE { t.Errorf("Error setting rating info: %+v", ts.ratingInfo) } if err != nil { @@ -1578,7 +1793,9 @@ func TestDebitDataUnits(t *testing.T) { if rifsBalance.BalanceMap[utils.DATA][0].GetValue() != 20 || rifsBalance.BalanceMap[utils.MONETARY][0].GetValue() != 21 { t.Log(ts.Increments) - t.Error("Error extracting minutes from balance: ", rifsBalance.BalanceMap[utils.DATA][0].GetValue(), rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) + t.Error("Error extracting minutes from balance: ", + rifsBalance.BalanceMap[utils.DATA][0].GetValue(), + rifsBalance.BalanceMap[utils.MONETARY][0].GetValue()) } } diff --git a/engine/callcost_test.go b/engine/callcost_test.go index 4f87cd25a..6ec384f94 100644 --- a/engine/callcost_test.go +++ b/engine/callcost_test.go @@ -27,7 +27,9 @@ import ( func TestSingleResultMerge(t *testing.T) { t1 := time.Date(2012, time.February, 2, 17, 0, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 2, 17, 1, 0, 0, time.UTC) - cd := &CallDescriptor{Direction: utils.OUT, Category: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{Direction: utils.OUT, Category: "0", + Tenant: "vdf", Subject: "rif", + Destination: "0256", TimeStart: t1, TimeEnd: t2} cc1, _ := cd.getCost() if cc1.Cost != 61 { t.Errorf("expected 61 was %v", cc1.Cost) @@ -50,7 +52,7 @@ func TestSingleResultMerge(t *testing.T) { t.Errorf("Exdpected 120 was %v", cc1.Cost) } d := cc1.UpdateRatedUsage() - if d != 2*time.Minute || cc1.RatedUsage != 120.0 { + if d != 2*time.Minute || cc1.RatedUsage != 120.0*float64(time.Second) { t.Errorf("error updating rating usage: %v, %v", d, cc1.RatedUsage) } } diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 5068eadfa..df0cafe9e 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -39,12 +39,21 @@ func init() { func populateDB() { ats := []*Action{ - &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}}}, - &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: &utils.ValueFormula{Static: 10}, DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, + &Action{ActionType: "*topup", + Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}}}, + &Action{ActionType: "*topup", + Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), + Weight: utils.Float64Pointer(20), + Value: &utils.ValueFormula{Static: 10 * float64(time.Second)}, + DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, } ats1 := []*Action{ - &Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 10}}, Weight: 10}, + &Action{ActionType: "*topup", + Balance: &BalanceFilter{ + Type: utils.StringPointer(utils.MONETARY), + Value: &utils.ValueFormula{Static: 10}}, Weight: 10}, &Action{ActionType: "*reset_account", Weight: 20}, } @@ -53,16 +62,21 @@ func populateDB() { BalanceMap: map[string]Balances{ utils.MONETARY: Balances{&Balance{Value: 50}}, utils.VOICE: Balances{ - &Balance{Value: 200, DestinationIDs: utils.NewStringMap("NAT"), Weight: 10}, - &Balance{Value: 100, DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, + &Balance{Value: 200 * float64(time.Second), + DestinationIDs: utils.NewStringMap("NAT"), Weight: 10}, + &Balance{Value: 100 * float64(time.Second), + DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, }}, } broker := &Account{ ID: "vdf:broker", BalanceMap: map[string]Balances{ utils.VOICE: Balances{ - &Balance{Value: 20, DestinationIDs: utils.NewStringMap("NAT"), Weight: 10, RatingSubject: "rif"}, - &Balance{Value: 100, DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, + &Balance{Value: 20 * float64(time.Second), + DestinationIDs: utils.NewStringMap("NAT"), + Weight: 10, RatingSubject: "rif"}, + &Balance{Value: 100 * float64(time.Second), + DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, }}, } luna := &Account{ @@ -77,8 +91,11 @@ func populateDB() { ID: "vdf:minitsboy", BalanceMap: map[string]Balances{ utils.VOICE: Balances{ - &Balance{Value: 20, DestinationIDs: utils.NewStringMap("NAT"), Weight: 10, RatingSubject: "rif"}, - &Balance{Value: 100, DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, + &Balance{Value: 20 * float64(time.Second), + DestinationIDs: utils.NewStringMap("NAT"), + Weight: 10, RatingSubject: "rif"}, + &Balance{Value: 100 * float64(time.Second), + DestinationIDs: utils.NewStringMap("RET"), Weight: 20}, }, utils.MONETARY: Balances{ &Balance{Value: 100, Weight: 10}, @@ -116,7 +133,9 @@ func populateDB() { func debitTest(t *testing.T, wg *sync.WaitGroup) { t1 := time.Date(2017, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2017, time.February, 2, 17, 30, 59, 0, time.UTC) - cd := &CallDescriptor{Direction: "*out", Category: "call", Tenant: "cgrates.org", Account: "moneyp", Subject: "nt", Destination: "49", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} + cd := &CallDescriptor{Direction: "*out", Category: "call", + Tenant: "cgrates.org", Account: "moneyp", Subject: "nt", + Destination: "49", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} if _, err := cd.Debit(); err != nil { t.Errorf("Error debiting balance: %s", err) } @@ -144,7 +163,9 @@ func TestSerialDebit(t *testing.T) { wg.Wait() t1 := time.Date(2017, time.February, 2, 17, 30, 0, 0, time.UTC) t2 := time.Date(2017, time.February, 2, 17, 30, 59, 0, time.UTC) - cd := &CallDescriptor{Direction: "*out", Category: "call", Tenant: "cgrates.org", Account: "moneyp", Subject: "nt", Destination: "49", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} + cd := &CallDescriptor{Direction: "*out", Category: "call", + Tenant: "cgrates.org", Account: "moneyp", Subject: "nt", + Destination: "49", TimeStart: t1, TimeEnd: t2, LoopIndex: 0} acc, err := cd.getAccount() if err != nil { @@ -152,14 +173,9 @@ func TestSerialDebit(t *testing.T) { } expBalance := initialBalance - float64(debitsToDo*60) if acc.BalanceMap[utils.MONETARY][0].GetValue() != expBalance { - t.Errorf("Balance does not match: %f, expected %f", acc.BalanceMap[utils.MONETARY][0].GetValue(), expBalance) + t.Errorf("Balance does not match: %f, expected %f", + acc.BalanceMap[utils.MONETARY][0].GetValue(), expBalance) } - /* - out, err := json.Marshal(acc) - if err == nil { - t.Log("Account: %s", string(out)) - } - */ } @@ -1308,9 +1324,11 @@ func TestDebitAndMaxDebit(t *testing.T) { if err1 != nil || err2 != nil { t.Error("Error debiting and/or maxdebiting: ", err1, err2) } - if cc1.Timespans[0].Increments[0].BalanceInfo.Unit.Value != 90 || - cc2.Timespans[0].Increments[0].BalanceInfo.Unit.Value != 80 { - t.Error("Error setting the Unit.Value: ", cc1.Timespans[0].Increments[0].BalanceInfo.Unit.Value, cc2.Timespans[0].Increments[0].BalanceInfo.Unit.Value) + if cc1.Timespans[0].Increments[0].BalanceInfo.Unit.Value != 90*float64(time.Second) || + cc2.Timespans[0].Increments[0].BalanceInfo.Unit.Value != 80*float64(time.Second) { + t.Error("Error setting the Unit.Value: ", + cc1.Timespans[0].Increments[0].BalanceInfo.Unit.Value, + cc2.Timespans[0].Increments[0].BalanceInfo.Unit.Value) } // make Unit.Values have the same value cc1.Timespans[0].Increments[0].BalanceInfo.Unit.Value = 0 @@ -1595,8 +1613,9 @@ func TestMaxDebitConsumesMinutes(t *testing.T) { LoopIndex: 0, DurationIndex: 0} cd1.MaxDebit() - if cd1.account.BalanceMap[utils.VOICE][0].GetValue() != 20 { - t.Error("Error using minutes: ", cd1.account.BalanceMap[utils.VOICE][0].GetValue()) + if cd1.account.BalanceMap[utils.VOICE][0].GetValue() != 20*float64(time.Second) { + t.Error("Error using minutes: ", + cd1.account.BalanceMap[utils.VOICE][0].GetValue()) } } @@ -1662,23 +1681,32 @@ func TestCDRefundIncrements(t *testing.T) { &Balance{Uuid: "moneya", Value: 100}, }, utils.VOICE: Balances{ - &Balance{Uuid: "minutea", Value: 10, Weight: 20, DestinationIDs: utils.StringMap{"NAT": true}}, - &Balance{Uuid: "minuteb", Value: 10, DestinationIDs: utils.StringMap{"RET": true}}, + &Balance{Uuid: "minutea", + Value: 10 * float64(time.Second), + Weight: 20, + DestinationIDs: utils.StringMap{"NAT": true}}, + &Balance{Uuid: "minuteb", + Value: 10 * float64(time.Second), + DestinationIDs: utils.StringMap{"RET": true}}, }, }, } dm.DataDB().SetAccount(ub) increments := Increments{ - &Increment{Cost: 2, BalanceInfo: &DebitInfo{Monetary: &MonetaryInfo{UUID: "moneya"}, AccountID: ub.ID}}, - &Increment{Cost: 2, Duration: 3 * time.Second, BalanceInfo: &DebitInfo{Unit: &UnitInfo{UUID: "minutea"}, Monetary: &MonetaryInfo{UUID: "moneya"}, AccountID: ub.ID}}, - &Increment{Duration: 4 * time.Second, BalanceInfo: &DebitInfo{Unit: &UnitInfo{UUID: "minuteb"}, AccountID: ub.ID}}, + &Increment{Cost: 2, BalanceInfo: &DebitInfo{ + Monetary: &MonetaryInfo{UUID: "moneya"}, AccountID: ub.ID}}, + &Increment{Cost: 2, Duration: 3 * time.Second, BalanceInfo: &DebitInfo{ + Unit: &UnitInfo{UUID: "minutea"}, + Monetary: &MonetaryInfo{UUID: "moneya"}, AccountID: ub.ID}}, + &Increment{Duration: 4 * time.Second, BalanceInfo: &DebitInfo{ + Unit: &UnitInfo{UUID: "minuteb"}, AccountID: ub.ID}}, } cd := &CallDescriptor{TOR: utils.VOICE, Increments: increments} cd.RefundIncrements() ub, _ = dm.DataDB().GetAccount(ub.ID) if ub.BalanceMap[utils.MONETARY][0].GetValue() != 104 || - ub.BalanceMap[utils.VOICE][0].GetValue() != 13 || - ub.BalanceMap[utils.VOICE][1].GetValue() != 14 { + ub.BalanceMap[utils.VOICE][0].GetValue() != 13*float64(time.Second) || + ub.BalanceMap[utils.VOICE][1].GetValue() != 14*float64(time.Second) { t.Error("Error refunding money: ", utils.ToIJSON(ub.BalanceMap)) } } @@ -1717,7 +1745,8 @@ func TestCDDebitBalanceSubjectWithFallback(t *testing.T) { ID: "TCDDBSWF:account1", BalanceMap: map[string]Balances{ utils.VOICE: Balances{ - &Balance{ID: "voice1", Value: 60, RatingSubject: "SubjTCDDBSWF"}, + &Balance{ID: "voice1", Value: 60 * float64(time.Second), + RatingSubject: "SubjTCDDBSWF"}, }}, } dm.DataDB().SetAccount(acnt) diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 069307102..7469a892e 100755 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -67,7 +67,7 @@ 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,1s,0s +GBP_70,0.000000,1,1s,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,1s,1s,0s @@ -163,10 +163,10 @@ SG3,*any,*lowest, ` actions = ` MINI,*topup_reset,,,,*monetary,*out,,,,,*unlimited,,10,10,false,false,10 -MINI,*topup,,,,*voice,*out,,NAT,test,,*unlimited,,100,10,false,false,10 +MINI,*topup,,,,*voice,*out,,NAT,test,,*unlimited,,100s,10,false,false,10 SHARED,*topup,,,,*monetary,*out,,,,SG1,*unlimited,,100,10,false,false,10 TOPUP10_AC,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,1,10,false,false,10 -TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,false,false,10 +TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40s,10,false,false,10 SE0,*topup_reset,,,,*monetary,*out,,,,SG2,*unlimited,,0,10,false,false,10 SE10,*topup_reset,,,,*monetary,*out,,,,SG2,*unlimited,,10,5,false,false,10 SE10,*topup,,,,*monetary,*out,,,,,*unlimited,,10,10,false,false,10 @@ -179,8 +179,8 @@ BLOCK,*topup,,,bfree,*monetary,*out,,,,,*unlimited,,20,10,false,false,10 BLOCK_EMPTY,*topup,,,bblocker,*monetary,*out,,NAT,,,*unlimited,,0,20,true,false,20 BLOCK_EMPTY,*topup,,,bfree,*monetary,*out,,,,,*unlimited,,20,10,false,false,10 FILTER,*topup,,"{""*and"":[{""Value"":{""*lt"":0}},{""Id"":{""*eq"":""*default""}}]}",bfree,*monetary,*out,,,,,*unlimited,,20,10,false,false,10 -EXP,*topup,,,,*voice,*out,,,,,*monthly,*any,300,10,false,false,10 -NOEXP,*topup,,,,*voice,*out,,,,,*unlimited,*any,50,10,false,false,10 +EXP,*topup,,,,*voice,*out,,,,,*monthly,*any,300s,10,false,false,10 +NOEXP,*topup,,,,*voice,*out,,,,,*unlimited,*any,50s,10,false,false,10 VF,*debit,,,,*monetary,*out,,,,,*unlimited,*any,"{""Method"":""*incremental"",""Params"":{""Units"":10, ""Interval"":""month"", ""Increment"":""day""}}",10,false,false,10 TOPUP_RST_GNR_1000,*topup_reset,"{""*voice"": 60.0,""*data"":1024.0,""*sms"":1.0}",,,*generic,*out,,*any,,,*unlimited,,1000,20,false,false,10 ` @@ -934,7 +934,7 @@ func TestLoadActions(t *testing.T) { Type: utils.StringPointer(utils.VOICE), Uuid: as1[1].Balance.Uuid, Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), - Value: &utils.ValueFormula{Static: 100}, + Value: &utils.ValueFormula{Static: 100 * float64(time.Second)}, Weight: utils.Float64Pointer(10), RatingSubject: utils.StringPointer("test"), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), diff --git a/engine/rateinterval.go b/engine/rateinterval.go index eec12cf68..c84a586c8 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -351,7 +351,7 @@ func (i *RateInterval) GetCost(duration, startSecond time.Duration) float64 { price, _, rateUnit := i.GetRateParameters(startSecond) price /= float64(rateUnit.Nanoseconds()) d := float64(duration.Nanoseconds()) - return d * price + return utils.Round(d*price, globalRoundingDecimals, utils.ROUNDING_MIDDLE) } // Gets the price for a the provided start second diff --git a/engine/responder_test.go b/engine/responder_test.go index e367761fe..5eb31fd53 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -69,17 +69,21 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { } else if maxSessionTime != -1 { t.Error("Unexpected maxSessionTime received: ", maxSessionTime) } - deTMobile := &Destination{Id: "DE_TMOBILE", Prefixes: []string{"+49151", "+49160", "+49170", "+49171", "+49175"}} + deTMobile := &Destination{Id: "DE_TMOBILE", + Prefixes: []string{"+49151", "+49160", "+49170", "+49171", "+49175"}} if err := dm.DataDB().SetDestination(deTMobile, utils.NonTransactional); err != nil { t.Error(err) } if err := dm.DataDB().SetReverseDestination(deTMobile, utils.NonTransactional); err != nil { t.Error(err) } - b10 := &Balance{Value: 10, Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} - b20 := &Balance{Value: 20, Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} + b10 := &Balance{Value: 10 * float64(time.Second), + Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} + b20 := &Balance{Value: 20 * float64(time.Second), + Weight: 10, DestinationIDs: utils.NewStringMap("DE_TMOBILE")} rifsAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "rif"), - BalanceMap: map[string]Balances{utils.VOICE: Balances{b10}}} + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{b10}}} dansAccount := &Account{ID: utils.ConcatenatedKey(testTenant, "dan"), BalanceMap: map[string]Balances{utils.VOICE: Balances{b20}}} if err := dm.DataDB().SetAccount(rifsAccount); err != nil { @@ -438,10 +442,18 @@ func TestResponderGetLCR(t *testing.T) { } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) } - bRif12 := &Balance{Value: 40, Weight: 10, DestinationIDs: utils.NewStringMap(dstDe.Id)} - bIvo12 := &Balance{Value: 60, Weight: 10, DestinationIDs: utils.NewStringMap(dstDe.Id)} - rif12sAccount := &Account{ID: utils.ConcatenatedKey("tenant12", "rif12"), BalanceMap: map[string]Balances{utils.VOICE: Balances{bRif12}}, AllowNegative: true} - ivo12sAccount := &Account{ID: utils.ConcatenatedKey("tenant12", "ivo12"), BalanceMap: map[string]Balances{utils.VOICE: Balances{bIvo12}}, AllowNegative: true} + bRif12 := &Balance{Value: 40 * float64(time.Second), + Weight: 10, DestinationIDs: utils.NewStringMap(dstDe.Id)} + bIvo12 := &Balance{Value: 60 * float64(time.Second), + Weight: 10, DestinationIDs: utils.NewStringMap(dstDe.Id)} + rif12sAccount := &Account{ + ID: utils.ConcatenatedKey("tenant12", "rif12"), + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{bRif12}}, AllowNegative: true} + ivo12sAccount := &Account{ + ID: utils.ConcatenatedKey("tenant12", "ivo12"), + BalanceMap: map[string]Balances{ + utils.VOICE: Balances{bIvo12}}, AllowNegative: true} for _, acnt := range []*Account{rif12sAccount, ivo12sAccount} { if err := dm.DataDB().SetAccount(acnt); err != nil { t.Error(err) @@ -461,7 +473,7 @@ func TestResponderGetLCR(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry) } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) + t.Errorf("Expecting: %s\n, received: %+v", utils.ToJSON(eLcLcr.SupplierCosts), utils.ToJSON(lcrLc.SupplierCosts)) } /* // Test *qos_threshold strategy here, diff --git a/general_tests/ddazmbl2_test.go b/general_tests/ddazmbl2_test.go index 910e6325f..24fa3d005 100644 --- a/general_tests/ddazmbl2_test.go +++ b/general_tests/ddazmbl2_test.go @@ -51,7 +51,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` sharedGroups := `` lcrs := `` actions := `TOPUP10_AC,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,0,10,false,false,10 -TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,false,false,10` +TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40s,10,false,false,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10 TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` @@ -135,7 +135,7 @@ func TestExecuteActions2(t *testing.T) { t.Error(err) } else if len(acnt.BalanceMap) != 2 { t.Error("Account does not have enough balances: ", acnt.BalanceMap) - } else if acnt.BalanceMap[utils.VOICE][0].Value != 40 { + } else if acnt.BalanceMap[utils.VOICE][0].Value != 40*float64(time.Second) { t.Error("Account does not have enough minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) } else if acnt.BalanceMap[utils.MONETARY][0].Value != 0 { t.Error("Account does not have enough monetary balance", acnt.BalanceMap[utils.MONETARY][0].Value) @@ -165,7 +165,7 @@ func TestDebit2(t *testing.T) { if len(acnt.BalanceMap) != 2 { t.Error("Wrong number of user balances found", acnt.BalanceMap) } - if acnt.BalanceMap[utils.VOICE][0].Value != 20 { + if acnt.BalanceMap[utils.VOICE][0].Value != 20*float64(time.Second) { t.Error("Account does not have expected minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) } for _, blnc := range acnt.BalanceMap[utils.MONETARY] { // Test negative balance for default one diff --git a/general_tests/ddazmbl3_test.go b/general_tests/ddazmbl3_test.go index 4230688cf..39f0fe81b 100644 --- a/general_tests/ddazmbl3_test.go +++ b/general_tests/ddazmbl3_test.go @@ -50,7 +50,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` *out,cgrates.org,call,discounted_minutes,2013-01-06T00:00:00Z,RP_UK_Mobile_BIG5_PKG,,` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40,10,false,false,10` + actions := `TOPUP10_AC1,*topup_reset,,,,*voice,*out,,DST_UK_Mobile_BIG5,discounted_minutes,,*unlimited,,40s,10,false,false,10` actionPlans := `TOPUP10_AT,TOPUP10_AC1,ASAP,10` actionTriggers := `` accountActions := `cgrates.org,12346,TOPUP10_AT,,,` @@ -133,7 +133,7 @@ func TestExecuteActions3(t *testing.T) { t.Error(err) } else if len(acnt.BalanceMap) != 1 { t.Error("Account does not have enough balances: ", acnt.BalanceMap) - } else if acnt.BalanceMap[utils.VOICE][0].Value != 40 { + } else if acnt.BalanceMap[utils.VOICE][0].Value != 40*float64(time.Second) { t.Error("Account does not have enough minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) } } @@ -161,7 +161,7 @@ func TestDebit3(t *testing.T) { if len(acnt.BalanceMap) != 2 { t.Error("Wrong number of user balances found", acnt.BalanceMap) } - if acnt.BalanceMap[utils.VOICE][0].Value != 20 { + if acnt.BalanceMap[utils.VOICE][0].Value != 20*float64(time.Second) { t.Error("Account does not have expected minutes in balance", acnt.BalanceMap[utils.VOICE][0].Value) } if acnt.BalanceMap[utils.MONETARY][0].Value != -0.01 { From 4643ff8f15f46815530073013ed05852e680ded8 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 17:27:39 +0200 Subject: [PATCH 26/75] Update integration test --- apier/v1/smgenericv1_it_test.go | 2 +- data/tariffplans/test/a1/ActionPlans.csv | 3 +- data/tariffplans/test/a1/Actions.csv | 3 +- data/tariffplans/test/a1/DestinationRates.csv | 1 + data/tariffplans/test/a1/RatingPlans.csv | 1 + data/tariffplans/test/a1/RatingProfiles.csv | 1 + data/tariffplans/test/a1/Timings.csv | 3 +- data/tariffplans/tutorial/Actions.csv | 4 +-- general_tests/a1_it_test.go | 4 +-- general_tests/acntacts_test.go | 2 +- general_tests/tut_smgeneric_it_test.go | 2 +- general_tests/tutorial_it_test.go | 2 +- sessionmanager/smg_it_test.go | 28 +++++++++---------- sessionmanager/smgbirpc_it_test.go | 10 +++---- 14 files changed, 36 insertions(+), 30 deletions(-) diff --git a/apier/v1/smgenericv1_it_test.go b/apier/v1/smgenericv1_it_test.go index 0f772734e..eb008ebaa 100644 --- a/apier/v1/smgenericv1_it_test.go +++ b/apier/v1/smgenericv1_it_test.go @@ -100,7 +100,7 @@ func TestSMGV1CacheStats(t *testing.T) { t.Error(reply) } var rcvStats *utils.CacheStats - expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, + expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} diff --git a/data/tariffplans/test/a1/ActionPlans.csv b/data/tariffplans/test/a1/ActionPlans.csv index 3c5d35121..a852fa4de 100644 --- a/data/tariffplans/test/a1/ActionPlans.csv +++ b/data/tariffplans/test/a1/ActionPlans.csv @@ -1,3 +1,4 @@ +#Id,ActionsId,TimingId,Weight PACKAGE_1,LOG,*asap,10 PACKAGE_1,LOG,FIRST_OF_YEAR_2020,10 -PACKAGE_2,LOG,FIRST_OF_YEAR_2020,10 \ No newline at end of file +PACKAGE_2,LOG,FIRST_OF_YEAR_2020,10 diff --git a/data/tariffplans/test/a1/Actions.csv b/data/tariffplans/test/a1/Actions.csv index 04864b6ef..6b10e6e73 100644 --- a/data/tariffplans/test/a1/Actions.csv +++ b/data/tariffplans/test/a1/Actions.csv @@ -1 +1,2 @@ -LOG,*log,,,,,,,,,,,,,,false,false,10 \ No newline at end of file +#ActionsId[0],Action[1],ExtraParameters[2],Filter[3],BalanceId[4],BalanceType[5],Directions[6],Categories[7],DestinationIds[8],RatingSubject[9],SharedGroup[10],ExpiryTime[11],TimingIds[12],Units[13],BalanceWeight[14],BalanceBlocker[15],BalanceDisabled[16],Weight[17] +LOG,*log,,,,,,,,,,,,,,false,false,10 diff --git a/data/tariffplans/test/a1/DestinationRates.csv b/data/tariffplans/test/a1/DestinationRates.csv index f3cf703cc..1e64ecac3 100644 --- a/data/tariffplans/test/a1/DestinationRates.csv +++ b/data/tariffplans/test/a1/DestinationRates.csv @@ -1 +1,2 @@ +#Id,DestinationId,RatesTag,RoundingMethod,RoundingDecimals,MaxCost,MaxCostStrategy DR_DATA1,*any,RT_DATA1,*up,5,, diff --git a/data/tariffplans/test/a1/RatingPlans.csv b/data/tariffplans/test/a1/RatingPlans.csv index a013a71da..34f413c1f 100644 --- a/data/tariffplans/test/a1/RatingPlans.csv +++ b/data/tariffplans/test/a1/RatingPlans.csv @@ -1 +1,2 @@ +#Id,DestinationRatesId,TimingTag,Weight RP_DATA1,DR_DATA1,*any,10 diff --git a/data/tariffplans/test/a1/RatingProfiles.csv b/data/tariffplans/test/a1/RatingProfiles.csv index 3ec883fe0..c72e83a99 100644 --- a/data/tariffplans/test/a1/RatingProfiles.csv +++ b/data/tariffplans/test/a1/RatingProfiles.csv @@ -1 +1,2 @@ +#Direction,Tenant,Category,Subject,ActivationTime,RatingPlanId,RatesFallbackSubject,CdrStatQueueIds *out,cgrates.org,data1,rpdata1,2015-01-01T00:00:00Z,RP_DATA1,, diff --git a/data/tariffplans/test/a1/Timings.csv b/data/tariffplans/test/a1/Timings.csv index 3a0c95d45..745a8cb9d 100644 --- a/data/tariffplans/test/a1/Timings.csv +++ b/data/tariffplans/test/a1/Timings.csv @@ -1 +1,2 @@ -FIRST_OF_YEAR_2020,2020,1,1,*any,00:00:00 \ No newline at end of file +#Tag,Years,Months,MonthDays,WeekDays,Time +FIRST_OF_YEAR_2020,2020,1,1,*any,00:00:00 diff --git a/data/tariffplans/tutorial/Actions.csv b/data/tariffplans/tutorial/Actions.csv index accbdefb3..f1ee20f9f 100644 --- a/data/tariffplans/tutorial/Actions.csv +++ b/data/tariffplans/tutorial/Actions.csv @@ -1,8 +1,8 @@ #ActionsId[0],Action[1],ExtraParameters[2],Filter[3],BalanceId[4],BalanceType[5],Directions[6],Categories[7],DestinationIds[8],RatingSubject[9],SharedGroup[10],ExpiryTime[11],TimingIds[12],Units[13],BalanceWeight[14],BalanceBlocker[15],BalanceDisabled[16],Weight[17] TOPUP_RST_10,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,10,10,false,false,10 TOPUP_RST_5,*topup_reset,,,,*monetary,*out,,*any,,,*unlimited,,5,20,false,false,10 -TOPUP_RST_5,*topup_reset,,,,*voice,*out,,DST_1002,SPECIAL_1002,,*unlimited,,90,20,false,false,10 -TOPUP_120_DST1003,*topup_reset,,,,*voice,*out,,DST_1003,,,*unlimited,,120,20,false,false,10 +TOPUP_RST_5,*topup_reset,,,,*voice,*out,,DST_1002,SPECIAL_1002,,*unlimited,,90s,20,false,false,10 +TOPUP_120_DST1003,*topup_reset,,,,*voice,*out,,DST_1003,,,*unlimited,,120s,20,false,false,10 TOPUP_RST_SHARED_5,*topup,,,,*monetary,*out,,*any,,SHARED_A,*unlimited,,5,10,false,false,10 SHARED_A_0,*topup_reset,,,,*monetary,*out,,*any,,SHARED_A,*unlimited,,0,10,false,false,10 TOPUP_RST_DATA_100,*topup_reset,,,,*data,*out,,*any,,,*unlimited,,102400,10,false,false,10 diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index cd9ca0110..4f9960e73 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -148,7 +148,7 @@ func TestA1itDataSession1(t *testing.T) { var maxUsage float64 if err := a1rpc.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 0.000010240 { + } else if maxUsage != 10240 { t.Error("Received: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ @@ -174,7 +174,7 @@ func TestA1itDataSession1(t *testing.T) { if err := a1rpc.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 0.002097152 { + } else if maxUsage != 2097152 { t.Error("Bad max usage: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index ea8cafa04..a1d84cdf1 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -43,7 +43,7 @@ func TestAcntActsLoadCsv(t *testing.T) { ratingProfiles := `` sharedGroups := `` lcrs := `` - actions := `TOPUP10_AC,*topup_reset,,,,*voice,*out,,*any,,,*unlimited,,10,10,false,false,10 + actions := `TOPUP10_AC,*topup_reset,,,,*voice,*out,,*any,,,*unlimited,,10s,10,false,false,10 DISABLE_ACNT,*disable_account,,,,,,,,,,,,,,false,false,10 ENABLE_ACNT,*enable_account,,,,,,,,,,,,,,false,false,10` actionPlans := `TOPUP10_AT,TOPUP10_AC,ASAP,10` diff --git a/general_tests/tut_smgeneric_it_test.go b/general_tests/tut_smgeneric_it_test.go index 22c112ead..4b1f25006 100644 --- a/general_tests/tut_smgeneric_it_test.go +++ b/general_tests/tut_smgeneric_it_test.go @@ -98,7 +98,7 @@ func TestTutSMGCacheStats(t *testing.T) { t.Error(reply) } var rcvStats *utils.CacheStats - expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, + expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index e93e367b4..d4532c3d3 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -102,7 +102,7 @@ func TestTutITCacheStats(t *testing.T) { t.Error(reply) } var rcvStats *utils.CacheStats - expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 9, + expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index bb5f1800c..af39cc12e 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -176,7 +176,7 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { } var acnt *engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"} - eAcntVal := 120.0 + eAcntVal := 120.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -202,7 +202,7 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } - eAcntVal = 150.0 + eAcntVal = 150.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -242,7 +242,7 @@ func TestSMGVoiceMixedRefund(t *testing.T) { } //var acnt *engine.Account //attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"} - eVoiceVal := 90.0 + eVoiceVal := 90.0 * float64(time.Second) eMoneyVal := 8.7399 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) @@ -269,7 +269,7 @@ func TestSMGVoiceMixedRefund(t *testing.T) { if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } - eVoiceVal = 90.0 + eVoiceVal = 90.0 * float64(time.Second) eMoneyVal = 8.79 if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) @@ -677,7 +677,7 @@ func TestSMGVoiceSessionTTL(t *testing.T) { func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestTTLWithRelocate", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestTTLWithRelocate"), - Value: utils.Float64Pointer(300), RatingSubject: utils.StringPointer("*zero50ms")} + Value: utils.Float64Pointer(300 * float64(time.Second)), RatingSubject: utils.StringPointer("*zero50ms")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) @@ -686,7 +686,7 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { } var acnt *engine.Account attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} - eAcntVal := 300.0 + eAcntVal := 300.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -724,7 +724,7 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { } else if aSessions[0].Usage != time.Duration(120)*time.Second { t.Errorf("Expecting 2m, received usage: %v", aSessions[0].Usage) } - eAcntVal = 180.0 + eAcntVal = 180.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -762,7 +762,7 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { } else if aSessions[0].Usage != time.Duration(150)*time.Second { t.Errorf("Expecting 2m30s, received usage: %v", aSessions[0].Usage) } - eAcntVal = 150.0 + eAcntVal = 150.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -771,7 +771,7 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { } time.Sleep(100 * time.Millisecond) - eAcntVal = 149.95 + eAcntVal = 149.95 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -802,7 +802,7 @@ func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestRelocateWithOriginIDPrefix", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestRelocateWithOriginIDPrefix"), - Value: utils.Float64Pointer(300), RatingSubject: utils.StringPointer("*zero1s")} + Value: utils.Float64Pointer(300 * float64(time.Second)), RatingSubject: utils.StringPointer("*zero1s")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) @@ -811,7 +811,7 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { } var acnt *engine.Account attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} - eAcntVal := 300.0 + eAcntVal := 300.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -849,7 +849,7 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { } else if aSessions[0].Usage != time.Duration(120)*time.Second { t.Errorf("Expecting 2m, received usage: %v", aSessions[0].Usage) } - eAcntVal = 180.0 + eAcntVal = 180.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -885,7 +885,7 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { } else if aSessions[0].Usage != time.Duration(150)*time.Second { t.Errorf("Expecting 2m30s, received usage: %v", aSessions[0].Usage) } - eAcntVal = 150.0 + eAcntVal = 150.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -913,7 +913,7 @@ func TestSMGVoiceRelocateWithOriginIDPrefix(t *testing.T) { utils.ACCID: "12372-1"}, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } - eAcntVal = 240 + eAcntVal = 240 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { diff --git a/sessionmanager/smgbirpc_it_test.go b/sessionmanager/smgbirpc_it_test.go index 2e8a14999..7e5a40854 100644 --- a/sessionmanager/smgbirpc_it_test.go +++ b/sessionmanager/smgbirpc_it_test.go @@ -111,7 +111,7 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), - Value: utils.Float64Pointer(0.01), + Value: utils.Float64Pointer(0.01 * float64(time.Second)), RatingSubject: utils.StringPointer("*zero1ms")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { @@ -122,7 +122,7 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { var acnt *engine.Account attrGetAcnt := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} - eAcntVal := 0.01 + eAcntVal := 0.01 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrGetAcnt, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -195,7 +195,7 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestSMGBiRPCSessionOriginatorTerminate", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestSMGBiRPCSessionOriginatorTerminate"), - Value: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("*zero1ms")} + Value: utils.Float64Pointer(1 * float64(time.Second)), RatingSubject: utils.StringPointer("*zero1ms")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) @@ -204,7 +204,7 @@ func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { } var acnt *engine.Account attrGetAcnt := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} - eAcntVal := 1.0 + eAcntVal := 1.0 * float64(time.Second) if err := smgRPC.Call("ApierV2.GetAccount", attrGetAcnt, &acnt); err != nil { t.Error(err) } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { @@ -242,7 +242,7 @@ func TestSMGBiRPCSessionOriginatorTerminate(t *testing.T) { time.Sleep(time.Duration(50 * time.Millisecond)) // Give time for debits to occur if err := smgRPC.Call("ApierV2.GetAccount", attrGetAcnt, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() > 0.995 { // FixMe: should be not 0.93? + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() > 0.995*float64(time.Second) { // FixMe: should be not 0.93? t.Errorf("Balance value: %f", acnt.BalanceMap[utils.VOICE].GetTotalValue()) } if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { From 756f8a5b5cc22762105ce40ad142d15db50990c1 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 17 Nov 2017 19:03:47 +0100 Subject: [PATCH 27/75] Diameter agent using time.Duration instead of float64 for rpc methods, *handler type available in CCA also --- agents/dmtagent.go | 9 +++++---- agents/dmtagent_it_test.go | 3 ++- agents/libdmt.go | 26 ++++++++++++++++---------- agents/libdmt_test.go | 18 ++++++++++++------ data/conf/samples/dmtagent/voice.json | 15 +++++++++++---- sessionmanager/smgeneric.go | 15 ++++++++++----- 6 files changed, 56 insertions(+), 30 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index fe4c237b9..29422817c 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -24,6 +24,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -129,7 +130,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro return false, ErrDiameterRatingFailed } } - var maxUsage float64 + var maxUsage time.Duration processorVars[CGRResultCode] = strconv.Itoa(diam.Success) processorVars[CGRError] = "" if reqProcessor.DryRun { // DryRun does not send over network @@ -146,7 +147,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro if ccr.CCRequestType == 3 { err = self.smg.Call("SMGenericV1.TerminateSession", smgEv, &rpl) } else if ccr.CCRequestType == 4 { - err = self.smg.Call("SMGenericV1.ChargeEvent", smgEv.Clone(), &maxUsage) + err = self.smg.Call("SMGenericV2.ChargeEvent", smgEv.Clone(), &maxUsage) if maxUsage == 0 { smgEv[utils.USAGE] = 0 // For CDR not to debit } @@ -182,12 +183,12 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro maxUsage = 0 } if prevMaxUsageStr, hasKey := processorVars[CGRMaxUsage]; hasKey { - prevMaxUsage, _ := strconv.ParseFloat(prevMaxUsageStr, 64) + prevMaxUsage, _ := utils.ParseDurationWithNanosecs(prevMaxUsageStr) if prevMaxUsage < maxUsage { maxUsage = prevMaxUsage } } - processorVars[CGRMaxUsage] = strconv.FormatFloat(maxUsage, 'f', -1, 64) + processorVars[CGRMaxUsage] = strconv.FormatInt(maxUsage.Nanoseconds(), 10) } if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, processorVars[CGRResultCode], false, self.cgrCfg.DiameterAgentCfg().Timezone); err != nil { diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index 121899d84..1c9db8688 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -254,7 +254,8 @@ func TestDmtAgentSendCCRInit(t *testing.T) { Usage: time.Duration(0), RunID: utils.DEFAULT_RUNID, ExtraFields: map[string]string{"Service-Context-Id": "voice@huawei.com"}, } - ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, + ccr := storedCdrToCCR(cdr, "UNIT_TEST", + daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) diff --git a/agents/libdmt.go b/agents/libdmt.go index a35a32df7..887ef5651 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -179,7 +179,8 @@ func avpValAsString(a *diam.AVP) string { } // Handler for meta functions -func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, error) { +func metaHandler(m *diam.Message, processorVars map[string]string, + tag, arg string, dur time.Duration) (string, error) { switch tag { case META_CCR_USAGE: var ok bool @@ -224,8 +225,9 @@ func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, e // metaValueExponent will multiply the float value with the exponent provided. // Expects 2 arguments in template separated by | -func metaValueExponent(m *diam.Message, argsTpl utils.RSRFields, roundingDecimals int) (string, error) { - valStr := composedFieldvalue(m, argsTpl, 0, nil) +func metaValueExponent(m *diam.Message, processorVars map[string]string, + argsTpl utils.RSRFields, roundingDecimals int) (string, error) { + valStr := composedFieldvalue(m, argsTpl, 0, processorVars) handlerArgs := strings.Split(valStr, utils.HandlerArgSep) if len(handlerArgs) != 2 { return "", errors.New("Unexpected number of arguments") @@ -242,8 +244,9 @@ func metaValueExponent(m *diam.Message, argsTpl utils.RSRFields, roundingDecimal return strconv.FormatFloat(utils.Round(res, roundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64), nil } -func metaSum(m *diam.Message, argsTpl utils.RSRFields, passAtIndex, roundingDecimals int) (string, error) { - valStr := composedFieldvalue(m, argsTpl, passAtIndex, nil) +func metaSum(m *diam.Message, processorVars map[string]string, + argsTpl utils.RSRFields, passAtIndex, roundingDecimals int) (string, error) { + valStr := composedFieldvalue(m, argsTpl, passAtIndex, processorVars) handlerArgs := strings.Split(valStr, utils.HandlerArgSep) var summed float64 for _, arg := range handlerArgs { @@ -376,7 +379,8 @@ func serializeAVPValueFromString(dictAVP *dict.AVP, valStr, timezone string) ([] } } -func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, extraParam interface{}, processorVars map[string]string) (fmtValOut string, err error) { +func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, + extraParam interface{}, processorVars map[string]string) (fmtValOut string, err error) { var outVal string passAtIndex := -1 passedAllFilters := true @@ -402,11 +406,11 @@ func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, extraParam interfa case utils.META_HANDLER: switch cfgFld.HandlerId { case META_VALUE_EXPONENT: - outVal, err = metaValueExponent(m, cfgFld.Value, 10) // FixMe: add here configured number of decimals + outVal, err = metaValueExponent(m, processorVars, cfgFld.Value, 10) // FixMe: add here configured number of decimals case META_SUM: - outVal, err = metaSum(m, cfgFld.Value, passAtIndex, 10) + outVal, err = metaSum(m, processorVars, cfgFld.Value, passAtIndex, 10) default: - outVal, err = metaHandler(m, cfgFld.HandlerId, cfgFld.Layout, extraParam.(time.Duration)) + outVal, err = metaHandler(m, processorVars, cfgFld.HandlerId, cfgFld.Layout, extraParam.(time.Duration)) if err != nil { utils.Logger.Warning(fmt.Sprintf(" Ignoring processing of metafunction: %s, error: %s", cfgFld.HandlerId, err.Error())) } @@ -699,7 +703,9 @@ func (self *CCA) SetProcessorAVPs(reqProcessor *config.DARequestProcessor, proce } return err } - if err := messageSetAVPsWithPath(self.diamMessage, splitIntoInterface(cfgFld.FieldId, utils.HIERARCHY_SEP), fmtOut, cfgFld.Append, self.timezone); err != nil { + if err := messageSetAVPsWithPath(self.diamMessage, + splitIntoInterface(cfgFld.FieldId, utils.HIERARCHY_SEP), + fmtOut, cfgFld.Append, self.timezone); err != nil { return err } if cfgFld.BreakOnSuccess { // don't look for another field diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index 0e776eae1..5189ff549 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -108,16 +108,17 @@ func TestMetaValueExponent(t *testing.T) { }), }, }) - if val, err := metaValueExponent(m, utils.ParseRSRFieldsMustCompile( + if val, err := metaValueExponent(m, nil, utils.ParseRSRFieldsMustCompile( "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 10); err != nil { t.Error(err) } else if val != "0.1" { t.Error("Received: ", val) } - if _, err = metaValueExponent(m, utils.ParseRSRFieldsMustCompile( - "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", - utils.INFIELD_SEP), 10); err == nil { + if _, err = metaValueExponent(m, nil, + utils.ParseRSRFieldsMustCompile( + "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", + utils.INFIELD_SEP), 10); err == nil { t.Error("Should have received error") // Insufficient number arguments } } @@ -140,12 +141,17 @@ func TestMetaSum(t *testing.T) { }), }, }) - if val, err := metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 0, 10); err != nil { + if val, err := metaSum(m, nil, + utils.ParseRSRFieldsMustCompile( + "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", + utils.INFIELD_SEP), 0, 10); err != nil { t.Error(err) } else if val != "9995" { t.Error("Received: ", val) } - if _, err = metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 0, 10); err == nil { + if _, err = metaSum(m, nil, utils.ParseRSRFieldsMustCompile( + "Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", + utils.INFIELD_SEP), 0, 10); err == nil { t.Error("Should have received error") // Insufficient number arguments } } diff --git a/data/conf/samples/dmtagent/voice.json b/data/conf/samples/dmtagent/voice.json index a1b369ea4..5d67b2bbf 100644 --- a/data/conf/samples/dmtagent/voice.json +++ b/data/conf/samples/dmtagent/voice.json @@ -17,7 +17,8 @@ {"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true}, {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "^*users", "mandatory": true}, {"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "^*users", "mandatory": true}, - {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "Service-Information>IN-Information>Real-Called-Number", "mandatory": true}, + {"tag": "Destination", "field_id": "Destination", "type": "*composed", + "value": "Service-Information>IN-Information>Real-Called-Number", "mandatory": true}, {"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true}, {"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true}, {"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*ccr_usage", "mandatory": true}, @@ -29,7 +30,9 @@ {"tag": "ResultCode", "field_filter":"CGRError(USER_NOT_FOUND)", "field_id": "Result-Code", "type": "*constant", "value": "5030"}, {"tag": "GrantedUnits", "field_filter":"CGRError(^$)", - "field_id": "Granted-Service-Unit>CC-Time", "type": "*composed", "value": "CGRMaxUsage", "mandatory": true}, + "field_id": "Granted-Service-Unit>CC-Time", + "type": "*handler", "handler_id": "*value_exponent", + "value": "CGRMaxUsage;^|-9", "mandatory": true}, ], }, { @@ -54,7 +57,9 @@ ], "cca_fields":[ // fields returned in CCA {"tag": "GrantedUnits", "field_filter":"CGRError(^$)", - "field_id": "Granted-Service-Unit>CC-Time", "type": "*composed", "value": "CGRMaxUsage", "mandatory": true}, + "field_id": "Granted-Service-Unit>CC-Time", + "type": "*handler", "handler_id": "*value_exponent", + "value": "CGRMaxUsage;^|-9", "mandatory": true}, ], }, { @@ -79,7 +84,9 @@ ], "cca_fields":[ // fields returned in CCA {"tag": "GrantedUnits", "field_filter":"CGRError(^$)", - "field_id": "Granted-Service-Unit>CC-Time", "type": "*composed", "value": "CGRMaxUsage", "mandatory": true}, + "field_id": "Granted-Service-Unit>CC-Time", + "type": "*handler", "handler_id": "*value_exponent", + "value": "CGRMaxUsage;^|-9", "mandatory": true}, ], }, ], diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index a6608b5c4..2a9e906d9 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -994,24 +994,28 @@ func (smg *SMGeneric) Call(serviceMethod string, args interface{}, reply interfa } // Part of utils.BiRPCServer to help internal connections do calls over rpcclient.RpcClientConnection interface -func (smg *SMGeneric) CallBiRPC(clnt rpcclient.RpcClientConnection, serviceMethod string, args interface{}, reply interface{}) error { +func (smg *SMGeneric) CallBiRPC(clnt rpcclient.RpcClientConnection, + serviceMethod string, args interface{}, reply interface{}) error { parts := strings.Split(serviceMethod, ".") if len(parts) != 2 { return rpcclient.ErrUnsupporteServiceMethod } // get method BiRPCV1.Method - method := reflect.ValueOf(smg).MethodByName("BiRPC" + parts[0][len(parts[0])-2:] + parts[1]) // Inherit the version V1 in the method name and add prefix + method := reflect.ValueOf(smg).MethodByName( + "BiRPC" + parts[0][len(parts[0])-2:] + parts[1]) // Inherit the version V1 in the method name and add prefix if !method.IsValid() { return rpcclient.ErrUnsupporteServiceMethod } // construct the params var clntVal reflect.Value if clnt == nil { - clntVal = reflect.New(reflect.TypeOf(new(utils.BiRPCInternalClient))).Elem() // Kinda cheat since we make up a type here + clntVal = reflect.New( + reflect.TypeOf(new(utils.BiRPCInternalClient))).Elem() // Kinda cheat since we make up a type here } else { clntVal = reflect.ValueOf(clnt) } - params := []reflect.Value{clntVal, reflect.ValueOf(args), reflect.ValueOf(reply)} + params := []reflect.Value{clntVal, reflect.ValueOf(args), + reflect.ValueOf(reply)} ret := method.Call(params) if len(ret) != 1 { return utils.ErrServerError @@ -1026,7 +1030,8 @@ func (smg *SMGeneric) CallBiRPC(clnt rpcclient.RpcClientConnection, serviceMetho return err } -func (smg *SMGeneric) BiRPCV1GetMaxUsage(clnt rpcclient.RpcClientConnection, ev SMGenericEvent, maxUsage *float64) error { +func (smg *SMGeneric) BiRPCV1GetMaxUsage(clnt rpcclient.RpcClientConnection, + ev SMGenericEvent, maxUsage *float64) error { maxUsageDur, err := smg.GetMaxUsage(ev) if err != nil { return utils.NewErrServerError(err) From 8fe85096e77fa817c2f8faedd5905f4d2c91a87f Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 14:11:57 +0200 Subject: [PATCH 28/75] Rename Get/Set/Rem StoredStatQueue -> Get/Set/Rem StoredStatQueueDrv --- engine/datamanager.go | 6 +++--- engine/onstor_it_test.go | 8 ++++---- engine/storage_interface.go | 6 +++--- engine/storage_map.go | 6 +++--- engine/storage_mongo_datadb.go | 6 +++--- engine/storage_redis.go | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/engine/datamanager.go b/engine/datamanager.go index 22b1241da..10b85353a 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -237,7 +237,7 @@ func (dm *DataManager) GetStatQueue(tenant, id string, skipCache bool, transacti return x.(*StatQueue), nil } } - ssq, err := dm.dataDB.GetStoredStatQueue(tenant, id) + ssq, err := dm.dataDB.GetStoredStatQueueDrv(tenant, id) if err != nil { if err == utils.ErrNotFound { cache.Set(key, nil, cacheCommit(transactionID), transactionID) @@ -257,12 +257,12 @@ func (dm *DataManager) SetStatQueue(sq *StatQueue) (err error) { if err != nil { return err } - return dm.dataDB.SetStoredStatQueue(ssq) + return dm.dataDB.SetStoredStatQueueDrv(ssq) } // RemStatQueue removes the StoredStatQueue and clears the cache for StatQueue func (dm *DataManager) RemStatQueue(tenant, id string, transactionID string) (err error) { - if err = dm.dataDB.RemStoredStatQueue(tenant, id); err != nil { + if err = dm.dataDB.RemStoredStatQueueDrv(tenant, id); err != nil { return } cache.RemKey(utils.StatQueuePrefix+utils.ConcatenatedKey(tenant, id), cacheCommit(transactionID), transactionID) diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index f6da2dc44..990f97d43 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -2027,18 +2027,18 @@ func testOnStorITCRUDStoredStatQueue(t *testing.T) { utils.MetaASR: msrshled, }, } - if err := onStor.DataDB().SetStoredStatQueue(sq); err != nil { + if err := onStor.DataDB().SetStoredStatQueueDrv(sq); err != nil { t.Error(err) } - if rcv, err := onStor.DataDB().GetStoredStatQueue(sq.Tenant, sq.ID); err != nil { + if rcv, err := onStor.DataDB().GetStoredStatQueueDrv(sq.Tenant, sq.ID); err != nil { t.Error(err) } else if !reflect.DeepEqual(sq, rcv) { t.Errorf("Expecting: %v, received: %v", sq, rcv) } - if err := onStor.DataDB().RemStoredStatQueue(sq.Tenant, sq.ID); err != nil { + if err := onStor.DataDB().RemStoredStatQueueDrv(sq.Tenant, sq.ID); err != nil { t.Error(err) } - if _, rcvErr := onStor.DataDB().GetStoredStatQueue(sq.Tenant, sq.ID); rcvErr != utils.ErrNotFound { + if _, rcvErr := onStor.DataDB().GetStoredStatQueueDrv(sq.Tenant, sq.ID); rcvErr != utils.ErrNotFound { t.Error(rcvErr) } } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 64e13c75a..a40b6a8ed 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -116,9 +116,9 @@ type DataDB interface { GetStatQueueProfileDrv(tenant string, ID string) (sq *StatQueueProfile, err error) SetStatQueueProfileDrv(sq *StatQueueProfile) (err error) RemStatQueueProfileDrv(tenant, id string) (err error) - GetStoredStatQueue(tenant, id string) (sq *StoredStatQueue, err error) - SetStoredStatQueue(sq *StoredStatQueue) (err error) - RemStoredStatQueue(tenant, id string) (err error) + GetStoredStatQueueDrv(tenant, id string) (sq *StoredStatQueue, err error) + SetStoredStatQueueDrv(sq *StoredStatQueue) (err error) + RemStoredStatQueueDrv(tenant, id string) (err error) GetThresholdProfileDrv(tenant string, ID string) (tp *ThresholdProfile, err error) SetThresholdProfileDrv(tp *ThresholdProfile) (err error) RemThresholdProfileDrv(tenant, id string) (err error) diff --git a/engine/storage_map.go b/engine/storage_map.go index 4eaaaff6c..10637d4d1 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -1242,7 +1242,7 @@ func (ms *MapStorage) RemStatQueueProfileDrv(tenant, id string) (err error) { } // GetStatQueue retrieves the stored metrics for a StatsQueue -func (ms *MapStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQueue, err error) { +func (ms *MapStorage) GetStoredStatQueueDrv(tenant, id string) (sq *StoredStatQueue, err error) { ms.mu.RLock() defer ms.mu.RUnlock() values, ok := ms.dict[utils.StatQueuePrefix+utils.ConcatenatedKey(tenant, id)] @@ -1254,7 +1254,7 @@ func (ms *MapStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQueue } // SetStatQueue stores the metrics for a StatsQueue -func (ms *MapStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { +func (ms *MapStorage) SetStoredStatQueueDrv(sq *StoredStatQueue) (err error) { ms.mu.Lock() defer ms.mu.Unlock() var result []byte @@ -1267,7 +1267,7 @@ func (ms *MapStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { } // RemStatQueue removes a StatsQueue -func (ms *MapStorage) RemStoredStatQueue(tenant, id string) (err error) { +func (ms *MapStorage) RemStoredStatQueueDrv(tenant, id string) (err error) { ms.mu.Lock() defer ms.mu.Unlock() delete(ms.dict, utils.StatQueuePrefix+utils.ConcatenatedKey(tenant, id)) diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index 31b3e6a27..e6ec27e24 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -1842,7 +1842,7 @@ func (ms *MongoStorage) RemStatQueueProfileDrv(tenant, id string) (err error) { } // GetStoredStatQueue retrieves a StoredStatQueue -func (ms *MongoStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQueue, err error) { +func (ms *MongoStorage) GetStoredStatQueueDrv(tenant, id string) (sq *StoredStatQueue, err error) { session, col := ms.conn(colSqs) defer session.Close() if err = col.Find(bson.M{"tenant": tenant, "id": id}).One(&sq); err != nil { @@ -1855,7 +1855,7 @@ func (ms *MongoStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQue } // SetStoredStatQueue stores the metrics for a StoredStatQueue -func (ms *MongoStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { +func (ms *MongoStorage) SetStoredStatQueueDrv(sq *StoredStatQueue) (err error) { session, col := ms.conn(colSqs) defer session.Close() _, err = col.Upsert(bson.M{"tenant": sq.Tenant, "id": sq.ID}, sq) @@ -1863,7 +1863,7 @@ func (ms *MongoStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { } // RemStatQueue removes stored metrics for a StoredStatQueue -func (ms *MongoStorage) RemStoredStatQueue(tenant, id string) (err error) { +func (ms *MongoStorage) RemStoredStatQueueDrv(tenant, id string) (err error) { session, col := ms.conn(colSqs) defer session.Close() err = col.Remove(bson.M{"tenant": tenant, "id": id}) diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 26be3a2b8..dd13e3a2e 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -1387,7 +1387,7 @@ func (rs *RedisStorage) RemStatQueueProfileDrv(tenant, id string) (err error) { } // GetStoredStatQueue retrieves the stored metrics for a StatsQueue -func (rs *RedisStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQueue, err error) { +func (rs *RedisStorage) GetStoredStatQueueDrv(tenant, id string) (sq *StoredStatQueue, err error) { key := utils.StatQueuePrefix + utils.ConcatenatedKey(tenant, id) var values []byte if values, err = rs.Cmd("GET", key).Bytes(); err != nil { @@ -1403,7 +1403,7 @@ func (rs *RedisStorage) GetStoredStatQueue(tenant, id string) (sq *StoredStatQue } // SetStoredStatQueue stores the metrics for a StatsQueue -func (rs *RedisStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { +func (rs *RedisStorage) SetStoredStatQueueDrv(sq *StoredStatQueue) (err error) { var result []byte result, err = rs.ms.Marshal(sq) if err != nil { @@ -1413,7 +1413,7 @@ func (rs *RedisStorage) SetStoredStatQueue(sq *StoredStatQueue) (err error) { } // RemStatQueue removes a StatsQueue -func (rs *RedisStorage) RemStoredStatQueue(tenant, id string) (err error) { +func (rs *RedisStorage) RemStoredStatQueueDrv(tenant, id string) (err error) { key := utils.StatQueuePrefix + utils.ConcatenatedKey(tenant, id) if err = rs.Cmd("DEL", key).Err; err != nil { return From a8df17d649cad256a95e1fee67d4937df21c7e09 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 31 Oct 2017 14:27:15 +0200 Subject: [PATCH 29/75] Add Get/Set ReqFilterIndexes in Datamanager --- engine/datamanager.go | 8 ++++++++ engine/filterindexer.go | 4 ++-- engine/onstor_it_test.go | 6 +++--- engine/storage_interface.go | 4 ++-- engine/storage_map.go | 4 ++-- engine/storage_mongo_datadb.go | 4 ++-- engine/storage_redis.go | 4 ++-- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/engine/datamanager.go b/engine/datamanager.go index 10b85353a..e917f1853 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -781,3 +781,11 @@ func (dm *DataManager) RemoveSubscriber(key string) (err error) { func (dm *DataManager) HasData(category, subject string) (has bool, err error) { return dm.DataDB().HasDataDrv(category, subject) } + +func (dm *DataManager) GetReqFilterIndexes(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { + return dm.DataDB().GetReqFilterIndexesDrv(dbKey) +} + +func (dm *DataManager) SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { + return dm.DataDB().SetReqFilterIndexesDrv(dbKey, indexes) +} diff --git a/engine/filterindexer.go b/engine/filterindexer.go index ada8b6b41..fd8d0c361 100644 --- a/engine/filterindexer.go +++ b/engine/filterindexer.go @@ -23,7 +23,7 @@ import ( ) func NewReqFilterIndexer(dm *DataManager, dbKey string) (*ReqFilterIndexer, error) { - indexes, err := dm.DataDB().GetReqFilterIndexes(dbKey) + indexes, err := dm.GetReqFilterIndexes(dbKey) if err != nil && err != utils.ErrNotFound { return nil, err } @@ -113,5 +113,5 @@ func (rfi *ReqFilterIndexer) IndexTPFilter(tpFltr *utils.TPFilter, itemID string // StoreIndexes handles storing the indexes to dataDB func (rfi *ReqFilterIndexer) StoreIndexes() error { - return rfi.dm.DataDB().SetReqFilterIndexes(rfi.dbKey, rfi.indexes) + return rfi.dm.SetReqFilterIndexes(rfi.dbKey, rfi.indexes) } diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index 990f97d43..de8588933 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -210,7 +210,7 @@ func testOnStorITSetReqFilterIndexes(t *testing.T) { }, }, } - if err := onStor.DataDB().SetReqFilterIndexes(utils.ResourceProfilesStringIndex, idxes); err != nil { + if err := onStor.SetReqFilterIndexes(utils.ResourceProfilesStringIndex, idxes); err != nil { t.Error(err) } } @@ -241,12 +241,12 @@ func testOnStorITGetReqFilterIndexes(t *testing.T) { }, }, } - if idxes, err := onStor.DataDB().GetReqFilterIndexes(utils.ResourceProfilesStringIndex); err != nil { + if idxes, err := onStor.GetReqFilterIndexes(utils.ResourceProfilesStringIndex); err != nil { t.Error(err) } else if !reflect.DeepEqual(eIdxes, idxes) { t.Errorf("Expecting: %+v, received: %+v", eIdxes, idxes) } - if _, err := onStor.DataDB().GetReqFilterIndexes("unknown_key"); err == nil || err != utils.ErrNotFound { + if _, err := onStor.GetReqFilterIndexes("unknown_key"); err == nil || err != utils.ErrNotFound { t.Error(err) } } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index a40b6a8ed..cf32fdaa5 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -110,8 +110,8 @@ type DataDB interface { RemoveTimingDrv(string) error GetLoadHistory(int, bool, string) ([]*utils.LoadInstance, error) AddLoadHistory(*utils.LoadInstance, int, string) error - GetReqFilterIndexes(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) - SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) + GetReqFilterIndexesDrv(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) + SetReqFilterIndexesDrv(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) MatchReqFilterIndex(dbKey, fieldName, fieldVal string) (itemIDs utils.StringMap, err error) GetStatQueueProfileDrv(tenant string, ID string) (sq *StatQueueProfile, err error) SetStatQueueProfileDrv(sq *StatQueueProfile) (err error) diff --git a/engine/storage_map.go b/engine/storage_map.go index 10637d4d1..b90a4e7ef 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -1149,7 +1149,7 @@ func (ms *MapStorage) RemoveTimingDrv(id string) error { return nil } -func (ms *MapStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { +func (ms *MapStorage) GetReqFilterIndexesDrv(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { ms.mu.RLock() defer ms.mu.RUnlock() values, ok := ms.dict[dbKey] @@ -1162,7 +1162,7 @@ func (ms *MapStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]map[ } return } -func (ms *MapStorage) SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { +func (ms *MapStorage) SetReqFilterIndexesDrv(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { ms.mu.Lock() defer ms.mu.Unlock() result, err := ms.ms.Marshal(indexes) diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index e6ec27e24..bbf831f14 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -1753,7 +1753,7 @@ func (ms *MongoStorage) RemoveTimingDrv(id string) (err error) { return nil } -func (ms *MongoStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { +func (ms *MongoStorage) GetReqFilterIndexesDrv(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { session, col := ms.conn(colRFI) defer session.Close() var result struct { @@ -1769,7 +1769,7 @@ func (ms *MongoStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]ma return result.Value, nil } -func (ms *MongoStorage) SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { +func (ms *MongoStorage) SetReqFilterIndexesDrv(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { session, col := ms.conn(colRFI) defer session.Close() _, err = col.Upsert(bson.M{"key": dbKey}, &struct { diff --git a/engine/storage_redis.go b/engine/storage_redis.go index dd13e3a2e..2a59daf3d 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -1252,7 +1252,7 @@ func (rs *RedisStorage) RemoveTimingDrv(id string) (err error) { return } -func (rs *RedisStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { +func (rs *RedisStorage) GetReqFilterIndexesDrv(dbKey string) (indexes map[string]map[string]utils.StringMap, err error) { mp, err := rs.Cmd("HGETALL", dbKey).Map() if err != nil { return @@ -1280,7 +1280,7 @@ func (rs *RedisStorage) GetReqFilterIndexes(dbKey string) (indexes map[string]ma return } -func (rs *RedisStorage) SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { +func (rs *RedisStorage) SetReqFilterIndexesDrv(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { mp := make(map[string]string) for fldName, fldValMp := range indexes { for fldVal, strMp := range fldValMp { From 0d4628379c3a15ebcbf49a918a72d11b4f48717f Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 7 Nov 2017 09:52:21 +0200 Subject: [PATCH 30/75] Add Get/Set CDRStatsQueue in DataManager --- engine/cdrstats_queue.go | 2 +- engine/cdrstatsiface.go | 2 +- engine/datamanager.go | 8 ++++++++ engine/onstor_it_test.go | 6 +++--- engine/storage_interface.go | 4 ++-- engine/storage_map.go | 4 ++-- engine/storage_mongo_datadb.go | 4 ++-- engine/storage_redis.go | 4 ++-- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/engine/cdrstats_queue.go b/engine/cdrstats_queue.go index d1150e67a..2ace31bda 100644 --- a/engine/cdrstats_queue.go +++ b/engine/cdrstats_queue.go @@ -104,7 +104,7 @@ func (sq *CDRStatsQueue) Save(db DataDB) { return } - if err := db.SetCdrStatsQueue(sq); err != nil { + if err := db.SetCdrStatsQueueDrv(sq); err != nil { utils.Logger.Err(fmt.Sprintf("Error saving cdr stats queue id %s: %v", sq.GetId(), err)) return } diff --git a/engine/cdrstatsiface.go b/engine/cdrstatsiface.go index f1c3afc40..6cdc8bb8a 100644 --- a/engine/cdrstatsiface.go +++ b/engine/cdrstatsiface.go @@ -254,7 +254,7 @@ func (s *Stats) UpdateQueues(css []*CdrStats, out *int) error { if sq == nil { sq = NewCDRStatsQueue(cs) // load queue from storage if exists - if saved, err := s.dm.DataDB().GetCdrStatsQueue(sq.GetId()); err == nil { + if saved, err := s.dm.GetCdrStatsQueue(sq.GetId()); err == nil { sq.Load(saved) } s.setupQueueSaver(sq) diff --git a/engine/datamanager.go b/engine/datamanager.go index e917f1853..dae3f5697 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -789,3 +789,11 @@ func (dm *DataManager) GetReqFilterIndexes(dbKey string) (indexes map[string]map func (dm *DataManager) SetReqFilterIndexes(dbKey string, indexes map[string]map[string]utils.StringMap) (err error) { return dm.DataDB().SetReqFilterIndexesDrv(dbKey, indexes) } + +func (dm *DataManager) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err error) { + return dm.DataDB().GetCdrStatsQueueDrv(key) +} + +func (dm *DataManager) SetCdrStatsQueue(sq *CDRStatsQueue) (err error) { + return dm.DataDB().SetCdrStatsQueueDrv(sq) +} diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index de8588933..a7371ebbc 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -1595,13 +1595,13 @@ func testOnStorITCRUDCdrStatsQueue(t *testing.T) { EventTime: time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC).Local(), }}, } - if _, rcvErr := onStor.DataDB().GetCdrStatsQueue(sq.GetId()); rcvErr != utils.ErrNotFound { + if _, rcvErr := onStor.GetCdrStatsQueue(sq.GetId()); rcvErr != utils.ErrNotFound { t.Error(rcvErr) } - if err := onStor.DataDB().SetCdrStatsQueue(sq); err != nil { + if err := onStor.SetCdrStatsQueue(sq); err != nil { t.Error(err) } - if rcv, err := onStor.DataDB().GetCdrStatsQueue(sq.GetId()); err != nil { + if rcv, err := onStor.GetCdrStatsQueue(sq.GetId()); err != nil { t.Error(err) } else if !reflect.DeepEqual(sq.Cdrs, rcv.Cdrs) { t.Errorf("Expecting: %v, received: %v", sq.Cdrs, rcv.Cdrs) diff --git a/engine/storage_interface.go b/engine/storage_interface.go index cf32fdaa5..7af81391a 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -85,8 +85,8 @@ type DataDB interface { GetAccount(string) (*Account, error) SetAccount(*Account) error RemoveAccount(string) error - GetCdrStatsQueue(string) (*CDRStatsQueue, error) - SetCdrStatsQueue(*CDRStatsQueue) error + GetCdrStatsQueueDrv(string) (*CDRStatsQueue, error) + SetCdrStatsQueueDrv(*CDRStatsQueue) error GetSubscribersDrv() (map[string]*SubscriberData, error) SetSubscriberDrv(string, *SubscriberData) error RemoveSubscriberDrv(string) error diff --git a/engine/storage_map.go b/engine/storage_map.go index b90a4e7ef..f13847bab 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -540,7 +540,7 @@ func (ms *MapStorage) RemoveAccount(key string) (err error) { return } -func (ms *MapStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err error) { +func (ms *MapStorage) GetCdrStatsQueueDrv(key string) (sq *CDRStatsQueue, err error) { ms.mu.RLock() defer ms.mu.RUnlock() if values, ok := ms.dict[utils.CDR_STATS_QUEUE_PREFIX+key]; ok { @@ -552,7 +552,7 @@ func (ms *MapStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err error return } -func (ms *MapStorage) SetCdrStatsQueue(sq *CDRStatsQueue) (err error) { +func (ms *MapStorage) SetCdrStatsQueueDrv(sq *CDRStatsQueue) (err error) { ms.mu.Lock() defer ms.mu.Unlock() result, err := ms.ms.Marshal(sq) diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index bbf831f14..e825ddb4a 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -1030,7 +1030,7 @@ func (ms *MongoStorage) RemoveAccount(key string) error { } -func (ms *MongoStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err error) { +func (ms *MongoStorage) GetCdrStatsQueueDrv(key string) (sq *CDRStatsQueue, err error) { var result struct { Key string Value *CDRStatsQueue @@ -1047,7 +1047,7 @@ func (ms *MongoStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err err return } -func (ms *MongoStorage) SetCdrStatsQueue(sq *CDRStatsQueue) (err error) { +func (ms *MongoStorage) SetCdrStatsQueueDrv(sq *CDRStatsQueue) (err error) { session, col := ms.conn(colStq) defer session.Close() _, err = col.Upsert(bson.M{"key": sq.GetId()}, &struct { diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 2a59daf3d..9c86f4ca5 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -588,7 +588,7 @@ func (rs *RedisStorage) RemoveAccount(key string) (err error) { } -func (rs *RedisStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err error) { +func (rs *RedisStorage) GetCdrStatsQueueDrv(key string) (sq *CDRStatsQueue, err error) { var values []byte if values, err = rs.Cmd("GET", utils.CDR_STATS_QUEUE_PREFIX+key).Bytes(); err != nil { if err == redis.ErrRespNil { // did not find the destination @@ -603,7 +603,7 @@ func (rs *RedisStorage) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err err return } -func (rs *RedisStorage) SetCdrStatsQueue(sq *CDRStatsQueue) (err error) { +func (rs *RedisStorage) SetCdrStatsQueueDrv(sq *CDRStatsQueue) (err error) { var result []byte if result, err = rs.ms.Marshal(sq); err != nil { return From 1670fc55299936905a97790e3f1903b6ecb3235c Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 7 Nov 2017 10:16:45 +0200 Subject: [PATCH 31/75] Add Get/Set/GetAll CdrStats in DataManager --- engine/cdrstats_queue.go | 2 +- engine/cdrstatsiface.go | 8 ++++---- engine/datamanager.go | 12 ++++++++++++ engine/loader_it_test.go | 2 +- engine/onstor_it_test.go | 8 ++++---- engine/storage_interface.go | 6 +++--- engine/storage_map.go | 6 +++--- engine/storage_mongo_datadb.go | 6 +++--- engine/storage_redis.go | 6 +++--- engine/tp_reader.go | 4 ++-- 10 files changed, 36 insertions(+), 24 deletions(-) diff --git a/engine/cdrstats_queue.go b/engine/cdrstats_queue.go index 2ace31bda..b20c56621 100644 --- a/engine/cdrstats_queue.go +++ b/engine/cdrstats_queue.go @@ -99,7 +99,7 @@ func (sq *CDRStatsQueue) Save(db DataDB) { defer sq.mux.Unlock() if sq.dirty { // save the conf - if err := db.SetCdrStats(sq.conf); err != nil { + if err := db.SetCdrStatsDrv(sq.conf); err != nil { utils.Logger.Err(fmt.Sprintf("Error saving cdr stats id %s: %v", sq.conf.Id, err)) return } diff --git a/engine/cdrstatsiface.go b/engine/cdrstatsiface.go index 6cdc8bb8a..1f0ade533 100644 --- a/engine/cdrstatsiface.go +++ b/engine/cdrstatsiface.go @@ -85,7 +85,7 @@ func (svr *queueSaver) stop() { func NewStats(dm *DataManager, saveInterval time.Duration) *Stats { cdrStats := &Stats{dm: dm, defaultSaveInterval: saveInterval} - if css, err := dm.DataDB().GetAllCdrStats(); err == nil { + if css, err := dm.GetAllCdrStats(); err == nil { cdrStats.UpdateQueues(css, nil) } else { utils.Logger.Err(fmt.Sprintf("Cannot load cdr stats: %v", err)) @@ -158,7 +158,7 @@ func (s *Stats) AddQueue(cs *CdrStats, out *int) error { s.queues[cs.Id] = sq } // save the conf - if err := s.dm.DataDB().SetCdrStats(cs); err != nil { + if err := s.dm.SetCdrStats(cs); err != nil { return err } if _, exists = s.queueSavers[sq.GetId()]; !exists { @@ -185,14 +185,14 @@ func (s *Stats) RemoveQueue(qID string, out *int) error { func (s *Stats) ReloadQueues(ids []string, out *int) error { if len(ids) == 0 { - if css, err := s.dm.DataDB().GetAllCdrStats(); err == nil { + if css, err := s.dm.GetAllCdrStats(); err == nil { s.UpdateQueues(css, nil) } else { return fmt.Errorf("Cannot load cdr stats: %v", err) } } for _, id := range ids { - if cs, err := s.dm.DataDB().GetCdrStats(id); err == nil { + if cs, err := s.dm.GetCdrStats(id); err == nil { s.AddQueue(cs, nil) } else { return err diff --git a/engine/datamanager.go b/engine/datamanager.go index dae3f5697..ba2f2370f 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -797,3 +797,15 @@ func (dm *DataManager) GetCdrStatsQueue(key string) (sq *CDRStatsQueue, err erro func (dm *DataManager) SetCdrStatsQueue(sq *CDRStatsQueue) (err error) { return dm.DataDB().SetCdrStatsQueueDrv(sq) } + +func (dm *DataManager) SetCdrStats(cs *CdrStats) error { + return dm.DataDB().SetCdrStatsDrv(cs) +} + +func (dm *DataManager) GetCdrStats(key string) (cs *CdrStats, err error) { + return dm.DataDB().GetCdrStatsDrv(key) +} + +func (dm *DataManager) GetAllCdrStats() (css []*CdrStats, err error) { + return dm.DataDB().GetAllCdrStatsDrv() +} diff --git a/engine/loader_it_test.go b/engine/loader_it_test.go index c5ffc920c..2ca9e484f 100755 --- a/engine/loader_it_test.go +++ b/engine/loader_it_test.go @@ -281,7 +281,7 @@ func TestLoaderITWriteToDatabase(t *testing.T) { } for k, sq := range loader.cdrStats { - rcv, err := loader.dm.DataDB().GetCdrStats(k) + rcv, err := loader.dm.GetCdrStats(k) // t.Log(utils.ToIJSON(sq)) // t.Log(utils.ToIJSON(rcv)) t.Log(k) diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index a7371ebbc..5a7012e26 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -1248,18 +1248,18 @@ func testOnStorITCRUDLCR(t *testing.T) { func testOnStorITCRUDCdrStats(t *testing.T) { cdrs := &CdrStats{Metrics: []string{ASR, PDD, ACD, TCD, ACC, TCC, DDC}} - if _, rcvErr := onStor.DataDB().GetCdrStats(""); rcvErr != utils.ErrNotFound { + if _, rcvErr := onStor.GetCdrStats(""); rcvErr != utils.ErrNotFound { t.Error(rcvErr) } - if err := onStor.DataDB().SetCdrStats(cdrs); err != nil { + if err := onStor.SetCdrStats(cdrs); err != nil { t.Error(err) } - if rcv, err := onStor.DataDB().GetCdrStats(""); err != nil { + if rcv, err := onStor.GetCdrStats(""); err != nil { t.Error(err) } else if !reflect.DeepEqual(cdrs.Metrics, rcv.Metrics) { t.Errorf("Expecting: %v, received: %v", cdrs.Metrics, rcv.Metrics) } - if rcv, err := onStor.DataDB().GetAllCdrStats(); err != nil { + if rcv, err := onStor.GetAllCdrStats(); err != nil { t.Error(err) } else if !reflect.DeepEqual([]*CdrStats{cdrs}[0].Metrics, rcv[0].Metrics) { t.Errorf("Expecting: %v, received: %v", []*CdrStats{cdrs}[0].Metrics, rcv[0].Metrics) diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 7af81391a..40c389626 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -61,9 +61,9 @@ type DataDB interface { UpdateReverseDestination(*Destination, *Destination, string) error GetLCRDrv(string) (*LCR, error) SetLCRDrv(*LCR) error - SetCdrStats(*CdrStats) error - GetCdrStats(string) (*CdrStats, error) - GetAllCdrStats() ([]*CdrStats, error) + SetCdrStatsDrv(*CdrStats) error + GetCdrStatsDrv(string) (*CdrStats, error) + GetAllCdrStatsDrv() ([]*CdrStats, error) GetDerivedChargersDrv(string) (*utils.DerivedChargers, error) SetDerivedChargers(string, *utils.DerivedChargers, string) error GetActionsDrv(string) (Actions, error) diff --git a/engine/storage_map.go b/engine/storage_map.go index f13847bab..55ae431ec 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -994,7 +994,7 @@ func (ms *MapStorage) SetDerivedChargers(key string, dcs *utils.DerivedChargers, return err } -func (ms *MapStorage) SetCdrStats(cs *CdrStats) error { +func (ms *MapStorage) SetCdrStatsDrv(cs *CdrStats) error { ms.mu.Lock() defer ms.mu.Unlock() result, err := ms.ms.Marshal(cs) @@ -1002,7 +1002,7 @@ func (ms *MapStorage) SetCdrStats(cs *CdrStats) error { return err } -func (ms *MapStorage) GetCdrStats(key string) (cs *CdrStats, err error) { +func (ms *MapStorage) GetCdrStatsDrv(key string) (cs *CdrStats, err error) { ms.mu.RLock() defer ms.mu.RUnlock() if values, ok := ms.dict[utils.CDR_STATS_PREFIX+key]; ok { @@ -1013,7 +1013,7 @@ func (ms *MapStorage) GetCdrStats(key string) (cs *CdrStats, err error) { return } -func (ms *MapStorage) GetAllCdrStats() (css []*CdrStats, err error) { +func (ms *MapStorage) GetAllCdrStatsDrv() (css []*CdrStats, err error) { ms.mu.RLock() defer ms.mu.RUnlock() for key, value := range ms.dict { diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index e825ddb4a..a5351057d 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -1635,14 +1635,14 @@ func (ms *MongoStorage) SetDerivedChargers(key string, dcs *utils.DerivedCharger return err } -func (ms *MongoStorage) SetCdrStats(cs *CdrStats) error { +func (ms *MongoStorage) SetCdrStatsDrv(cs *CdrStats) error { session, col := ms.conn(colCrs) defer session.Close() _, err := col.Upsert(bson.M{"id": cs.Id}, cs) return err } -func (ms *MongoStorage) GetCdrStats(key string) (cs *CdrStats, err error) { +func (ms *MongoStorage) GetCdrStatsDrv(key string) (cs *CdrStats, err error) { cs = new(CdrStats) session, col := ms.conn(colCrs) defer session.Close() @@ -1655,7 +1655,7 @@ func (ms *MongoStorage) GetCdrStats(key string) (cs *CdrStats, err error) { return } -func (ms *MongoStorage) GetAllCdrStats() (css []*CdrStats, err error) { +func (ms *MongoStorage) GetAllCdrStatsDrv() (css []*CdrStats, err error) { session, col := ms.conn(colCrs) defer session.Close() iter := col.Find(nil).Iter() diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 9c86f4ca5..1c350ee6e 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -1120,7 +1120,7 @@ func (rs *RedisStorage) SetDerivedChargers(key string, dcs *utils.DerivedCharger return } -func (rs *RedisStorage) SetCdrStats(cs *CdrStats) error { +func (rs *RedisStorage) SetCdrStatsDrv(cs *CdrStats) error { marshaled, err := rs.ms.Marshal(cs) if err != nil { return err @@ -1128,7 +1128,7 @@ func (rs *RedisStorage) SetCdrStats(cs *CdrStats) error { return rs.Cmd("SET", utils.CDR_STATS_PREFIX+cs.Id, marshaled).Err } -func (rs *RedisStorage) GetCdrStats(key string) (cs *CdrStats, err error) { +func (rs *RedisStorage) GetCdrStatsDrv(key string) (cs *CdrStats, err error) { var values []byte if values, err = rs.Cmd("GET", utils.CDR_STATS_PREFIX+key).Bytes(); err != nil { if err == redis.ErrRespNil { // did not find the destination @@ -1142,7 +1142,7 @@ func (rs *RedisStorage) GetCdrStats(key string) (cs *CdrStats, err error) { return } -func (rs *RedisStorage) GetAllCdrStats() (css []*CdrStats, err error) { +func (rs *RedisStorage) GetAllCdrStatsDrv() (css []*CdrStats, err error) { keys, err := rs.Cmd("KEYS", utils.CDR_STATS_PREFIX+"*").List() if err != nil { return nil, err diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 26b264004..79cab2b87 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -1462,7 +1462,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) { } } for _, stat := range tpr.cdrStats { - if err := tpr.dm.DataDB().SetCdrStats(stat); err != nil { + if err := tpr.dm.SetCdrStats(stat); err != nil { return err } } @@ -2015,7 +2015,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err log.Print("CDR Stats Queues:") } for _, sq := range tpr.cdrStats { - err = tpr.dm.DataDB().SetCdrStats(sq) + err = tpr.dm.SetCdrStats(sq) if err != nil { return err } From 6c744e9c5b707025bce1a6644aa2670096486d73 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 7 Nov 2017 13:28:02 +0200 Subject: [PATCH 32/75] Update ExportCDRs in apier --- apier/v1/cdre.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go index dd3b89e85..a541fc7a1 100644 --- a/apier/v1/cdre.go +++ b/apier/v1/cdre.go @@ -25,17 +25,17 @@ import ( "encoding/json" "errors" "fmt" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" "io/ioutil" + "net/url" "os" "path" "strconv" "strings" "time" "unicode/utf8" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" ) func (self *ApierV1) ExportCdrsToZipString(attr utils.AttrExpFileCdrs, reply *string) error { @@ -270,9 +270,16 @@ func (self *ApierV1) ExportCDRs(arg ArgExportCDRs, reply *RplExportedCDRs) (err if arg.ExportFileName != nil && len(*arg.ExportFileName) != 0 { fileName = *arg.ExportFileName } - filePath := path.Join(eDir, fileName) - if exportFormat == utils.DRYRUN { + var filePath string + switch exportFormat { + case utils.MetaFileFWV, utils.MetaFileCSV: + filePath = path.Join(eDir, fileName) + case utils.DRYRUN: filePath = utils.DRYRUN + default: + u, _ := url.Parse(eDir) + u.Path = path.Join(u.Path, fileName) + filePath = u.String() } usageMultiplyFactor := exportTemplate.UsageMultiplyFactor for k, v := range arg.UsageMultiplyFactor { @@ -296,7 +303,8 @@ func (self *ApierV1) ExportCDRs(arg ArgExportCDRs, reply *RplExportedCDRs) (err } else if len(cdrs) == 0 { return } - cdrexp, err := engine.NewCDRExporter(cdrs, exportTemplate, exportFormat, filePath, utils.META_NONE, exportID, + cdrexp, err := engine.NewCDRExporter(cdrs, exportTemplate, exportFormat, + filePath, utils.META_NONE, exportID, synchronous, attempts, fieldSep, usageMultiplyFactor, costMultiplyFactor, roundingDecimals, self.Config.HttpSkipTlsVerify, self.HTTPPoster) if err != nil { From 8ed051e75365ac389a6abecb06f1fa15e9df0e13 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 7 Nov 2017 13:35:36 +0200 Subject: [PATCH 33/75] Update internal/external adress --- apier/v1/cdre.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go index a541fc7a1..177636164 100644 --- a/apier/v1/cdre.go +++ b/apier/v1/cdre.go @@ -25,9 +25,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" "io/ioutil" "net/url" "os" @@ -36,6 +33,10 @@ import ( "strings" "time" "unicode/utf8" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" ) func (self *ApierV1) ExportCdrsToZipString(attr utils.AttrExpFileCdrs, reply *string) error { From 86141e14b352cd6ad54852fe12e1b5944b742414 Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Tue, 7 Nov 2017 12:24:33 +0000 Subject: [PATCH 34/75] Added migration from action triggers to thresholds and cdrstats to stats --- data/storage/migrator/mysql_tables_update.sql | 10 +- data/storage/migrator/usage_float_to_int.sql | 4 + migrator/migrator.go | 4 + migrator/migrator_it_test.go | 297 ++++++++++++++--- migrator/stats.go | 313 ++++++++++++++++++ migrator/stats_test.go | 139 ++++++++ migrator/thresholds.go | 296 +++++++++++++++++ migrator/thresholds_test.go | 89 +++++ migrator/v1datadb.go | 4 + migrator/v1mongo_data.go | 46 +++ migrator/v1redis.go | 83 +++++ utils/consts.go | 3 + 12 files changed, 1234 insertions(+), 54 deletions(-) create mode 100644 data/storage/migrator/usage_float_to_int.sql create mode 100644 migrator/stats.go create mode 100644 migrator/stats_test.go create mode 100644 migrator/thresholds.go create mode 100644 migrator/thresholds_test.go diff --git a/data/storage/migrator/mysql_tables_update.sql b/data/storage/migrator/mysql_tables_update.sql index da020828f..25007ef41 100755 --- a/data/storage/migrator/mysql_tables_update.sql +++ b/data/storage/migrator/mysql_tables_update.sql @@ -68,12 +68,4 @@ CREATE TABLE versions ( `version` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `item` (`item`) -); - - - - -ALTER TABLE cdrs CHANGE COLUMN `usage` `usage_old` DECIMAL(30,9); -ALTER TABLE cdrs ADD `usage` DECIMAL(30); -UPDATE cdrs SET `usage` = `usage_old` * 1000000000 WHERE usage_old IS NOT NULL; -ALTER TABLE cdrs DROP COLUMN usage_old; \ No newline at end of file +); \ No newline at end of file diff --git a/data/storage/migrator/usage_float_to_int.sql b/data/storage/migrator/usage_float_to_int.sql new file mode 100644 index 000000000..9061b2ceb --- /dev/null +++ b/data/storage/migrator/usage_float_to_int.sql @@ -0,0 +1,4 @@ +ALTER TABLE cdrs CHANGE COLUMN `usage` `usage_old` DECIMAL(30,9); +ALTER TABLE cdrs ADD `usage` BIGINT; +UPDATE cdrs SET `usage` = `usage_old` * 1000000000 WHERE usage_old IS NOT NULL; +ALTER TABLE cdrs DROP COLUMN usage_old; \ No newline at end of file diff --git a/migrator/migrator.go b/migrator/migrator.go index e712ba861..4f1647e71 100755 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -105,6 +105,10 @@ func (m *Migrator) Migrate(taskIDs []string) (err error, stats map[string]int) { err = m.migrateActions() case utils.MetaSharedGroups: err = m.migrateSharedGroups() + case utils.MetaStats: + err = m.migrateStats() + case utils.MetaThresholds: + err = m.migrateStats() } } for k, v := range m.stats { diff --git a/migrator/migrator_it_test.go b/migrator/migrator_it_test.go index 9f4a88445..f4a0aa13a 100644 --- a/migrator/migrator_it_test.go +++ b/migrator/migrator_it_test.go @@ -44,6 +44,7 @@ var sTestsITMigrator = []func(t *testing.T){ testMigratorActionTriggers, testMigratorActions, testMigratorSharedGroups, + testMigratorStats, testFlush, } @@ -71,7 +72,7 @@ func TestMigratorITPostgresConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, storDB, postgresITCfg.StorDBType, oldDataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, oldstorDB, postgresITCfg.StorDBType) + mig, err = NewMigrator(dataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, storDB, postgresITCfg.StorDBType, oldDataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, oldstorDB, postgresITCfg.StorDBType, false) if err != nil { log.Fatal(err) } @@ -79,6 +80,7 @@ func TestMigratorITPostgresConnect(t *testing.T) { func TestMigratorITPostgres(t *testing.T) { dbtype = utils.REDIS + log.Print("REDIS+POSTGRES") for _, stest := range sTestsITMigrator { t.Run("TestITMigratorOnPostgres", stest) } @@ -108,7 +110,7 @@ func TestMigratorITRedisConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, storDB, mysqlITCfg.StorDBType, oldDataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, oldstorDB, mysqlITCfg.StorDBType) + mig, err = NewMigrator(dataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, storDB, mysqlITCfg.StorDBType, oldDataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, oldstorDB, mysqlITCfg.StorDBType, false) if err != nil { log.Fatal(err) } @@ -116,6 +118,7 @@ func TestMigratorITRedisConnect(t *testing.T) { func TestMigratorITRedis(t *testing.T) { dbtype = utils.REDIS + log.Print("REDIS+MYSQL") for _, stest := range sTestsITMigrator { t.Run("TestITMigratorOnRedis", stest) } @@ -145,7 +148,7 @@ func TestMigratorITMongoConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, storDB, mgoITCfg.StorDBType, oldDataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, oldstorDB, mgoITCfg.StorDBType) + mig, err = NewMigrator(dataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, storDB, mgoITCfg.StorDBType, oldDataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, oldstorDB, mgoITCfg.StorDBType, false) if err != nil { log.Fatal(err) } @@ -153,27 +156,16 @@ func TestMigratorITMongoConnect(t *testing.T) { func TestMigratorITMongo(t *testing.T) { dbtype = utils.MONGO + log.Print("MONGO") for _, stest := range sTestsITMigrator { t.Run("TestITMigratorOnMongo", stest) } } func testFlush(t *testing.T) { - switch { - case dbtype == utils.REDIS: - dataDB := mig.dataDB.(*engine.RedisStorage) - err := dataDB.Cmd("FLUSHALL").Err - if err != nil { - t.Error("Error when flushing Redis ", err.Error()) - } - case dbtype == utils.MONGO: - err := mig.dataDB.Flush("") - if err != nil { - t.Error("Error when flushing Mongo ", err.Error()) - } - } - if err = SetDBVersions(mig.dataDB); err != nil { - return err + mig.dm.DataDB().Flush("") + if err := engine.SetDBVersions(mig.dm.DataDB()); err != nil { + t.Error("Error ", err.Error()) } } @@ -192,11 +184,11 @@ func testMigratorAccounts(t *testing.T) { if err != nil { t.Error("Error when setting v1 acc ", err.Error()) } - err = mig.Migrate(utils.MetaAccounts) + err, _ = mig.Migrate([]string{utils.MetaAccounts}) if err != nil { t.Error("Error when migrating accounts ", err.Error()) } - result, err := mig.dataDB.GetAccount(testAccount.ID) + result, err := mig.dm.DataDB().GetAccount(testAccount.ID) if err != nil { t.Error("Error when getting account ", err.Error()) } @@ -210,11 +202,11 @@ func testMigratorAccounts(t *testing.T) { if err != nil { t.Error("Error when marshaling ", err.Error()) } - err = mig.Migrate(utils.MetaAccounts) + err, _ = mig.Migrate([]string{utils.MetaAccounts}) if err != nil { t.Error("Error when migrating accounts ", err.Error()) } - result, err := mig.dataDB.GetAccount(testAccount.ID) + result, err := mig.dm.DataDB().GetAccount(testAccount.ID) if err != nil { t.Error("Error when getting account ", err.Error()) } @@ -233,11 +225,11 @@ func testMigratorActionPlans(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionPlan ", err.Error()) } - err = mig.Migrate(utils.MetaActionPlans) + err, _ = mig.Migrate([]string{utils.MetaActionPlans}) if err != nil { t.Error("Error when migrating ActionPlans ", err.Error()) } - result, err := mig.dataDB.GetActionPlan(ap.Id, true, utils.NonTransactional) + result, err := mig.dm.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionPlan ", err.Error()) } @@ -253,11 +245,11 @@ func testMigratorActionPlans(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionPlans ", err.Error()) } - err = mig.Migrate(utils.MetaActionPlans) + err, _ = mig.Migrate([]string{utils.MetaActionPlans}) if err != nil { t.Error("Error when migrating ActionPlans ", err.Error()) } - result, err := mig.dataDB.GetActionPlan(ap.Id, true, utils.NonTransactional) + result, err := mig.dm.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionPlan ", err.Error()) } @@ -309,11 +301,11 @@ func testMigratorActionTriggers(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionTriggers ", err.Error()) } - err = mig.Migrate(utils.MetaActionTriggers) + err, _ = mig.Migrate([]string{utils.MetaActionTriggers}) if err != nil { t.Error("Error when migrating ActionTriggers ", err.Error()) } - result, err := mig.dataDB.GetActionTriggers((*v1atrs)[0].Id, true, utils.NonTransactional) + result, err := mig.dm.GetActionTriggers((*v1atrs)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionTriggers ", err.Error()) } @@ -381,7 +373,7 @@ func testMigratorActionTriggers(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Blocker, result[0].Balance.Blocker) } case dbtype == utils.MONGO: - err := mig.Migrate(utils.MetaActionTriggers) + err, _ := mig.Migrate([]string{utils.MetaActionTriggers}) if err != nil && err != utils.ErrNotImplemented { t.Error("Error when migrating ActionTriggers ", err.Error()) } @@ -398,11 +390,11 @@ func testMigratorActions(t *testing.T) { if err != nil { t.Error("Error when setting v1 Actions ", err.Error()) } - err = mig.Migrate(utils.MetaActions) + err, _ = mig.Migrate([]string{utils.MetaActions}) if err != nil { t.Error("Error when migrating Actions ", err.Error()) } - result, err := mig.dataDB.GetActions((*v1act)[0].Id, true, utils.NonTransactional) + result, err := mig.dm.GetActions((*v1act)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Actions ", err.Error()) } @@ -415,11 +407,11 @@ func testMigratorActions(t *testing.T) { if err != nil { t.Error("Error when setting v1 Actions ", err.Error()) } - err = mig.Migrate(utils.MetaActions) + err, _ = mig.Migrate([]string{utils.MetaActions}) if err != nil { t.Error("Error when migrating Actions ", err.Error()) } - result, err := mig.dataDB.GetActions((*v1act)[0].Id, true, utils.NonTransactional) + result, err := mig.dm.GetActions((*v1act)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Actions ", err.Error()) } @@ -430,14 +422,14 @@ func testMigratorActions(t *testing.T) { } func testMigratorSharedGroups(t *testing.T) { - v1sg := &v1SharedGroup{ + v1sqp := &v1SharedGroup{ Id: "Test", AccountParameters: map[string]*engine.SharingParameters{ "test": &engine.SharingParameters{Strategy: "*highest"}, }, MemberIds: []string{"1", "2", "3"}, } - sg := &engine.SharedGroup{ + sqp := &engine.SharedGroup{ Id: "Test", AccountParameters: map[string]*engine.SharingParameters{ "test": &engine.SharingParameters{Strategy: "*highest"}, @@ -446,37 +438,252 @@ func testMigratorSharedGroups(t *testing.T) { } switch { case dbtype == utils.REDIS: - err := mig.oldDataDB.setV1SharedGroup(v1sg) + err := mig.oldDataDB.setV1SharedGroup(v1sqp) if err != nil { t.Error("Error when setting v1 SharedGroup ", err.Error()) } - err = mig.Migrate(utils.MetaSharedGroups) + err, _ = mig.Migrate([]string{utils.MetaSharedGroups}) if err != nil { t.Error("Error when migrating SharedGroup ", err.Error()) } - result, err := mig.dataDB.GetSharedGroup(v1sg.Id, true, utils.NonTransactional) + result, err := mig.dm.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting SharedGroup ", err.Error()) } - if !reflect.DeepEqual(sg, result) { - t.Errorf("Expecting: %+v, received: %+v", sg, result) + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) } case dbtype == utils.MONGO: - err := mig.oldDataDB.setV1SharedGroup(v1sg) + err := mig.oldDataDB.setV1SharedGroup(v1sqp) if err != nil { t.Error("Error when setting v1 SharedGroup ", err.Error()) } - err = mig.Migrate(utils.MetaSharedGroups) + err, _ = mig.Migrate([]string{utils.MetaSharedGroups}) if err != nil { t.Error("Error when migrating SharedGroup ", err.Error()) } - result, err := mig.dataDB.GetSharedGroup(v1sg.Id, true, utils.NonTransactional) + result, err := mig.dm.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting SharedGroup ", err.Error()) } - if !reflect.DeepEqual(sg, result) { - t.Errorf("Expecting: %+v, received: %+v", sg, result) + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) } } } + +func testMigratorStats(t *testing.T) { + tim := time.Date(2012, time.February, 27, 23, 59, 59, 0, time.UTC).Local() + var filters []*engine.RequestFilter + v1Sts := &v1Stat{ + Id: "test", // Config id, unique per config instance + QueueLength: 10, // Number of items in the stats buffer + TimeWindow: time.Duration(1) * time.Second, // Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow + SaveInterval: time.Duration(1) * time.Second, + Metrics: []string{"ASR", "ACD", "ACC"}, + SetupInterval: []time.Time{time.Now()}, + TOR: []string{}, + CdrHost: []string{}, + CdrSource: []string{}, + ReqType: []string{}, + Direction: []string{}, + Tenant: []string{}, + Category: []string{}, + Account: []string{}, + Subject: []string{}, + DestinationIds: []string{}, + UsageInterval: []time.Duration{1 * time.Second}, + PddInterval: []time.Duration{1 * time.Second}, + Supplier: []string{}, + DisconnectCause: []string{}, + MediationRunIds: []string{}, + RatedAccount: []string{}, + RatedSubject: []string{}, + CostInterval: []float64{}, + Triggers: engine.ActionTriggers{ + &engine.ActionTrigger{ + ID: "Test", + Balance: &engine.BalanceFilter{ + ID: utils.StringPointer("TESTB"), + Timings: []*engine.RITiming{}, + ExpirationDate: utils.TimePointer(tim), + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ExpirationDate: tim, + LastExecutionTime: tim, + ActivationDate: tim, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, + ActionsID: "TEST_ACTIONS", + Executed: true, + }, + }, + } + + x, _ := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "SetupInterval", []string{v1Sts.SetupInterval[0].String()}) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaGreaterOrEqual, "UsageInterval", []string{v1Sts.UsageInterval[0].String()}) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaGreaterOrEqual, "PddInterval", []string{v1Sts.PddInterval[0].String()}) + filters = append(filters, x) + + filter := &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: v1Sts.Id, RequestFilters: filters} + + sqp := &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "test", + FilterIDs: []string{v1Sts.Id}, + QueueLength: 10, + TTL: time.Duration(0) * time.Second, + Metrics: []string{"*asr", "*acd", "*acc"}, + Thresholds: []string{"Test"}, + Blocker: false, + Stored: true, + Weight: float64(0), + MinItems: 0, + } + sq := &engine.StatQueue{Tenant: config.CgrConfig().DefaultTenant, + ID: v1Sts.Id, + SQMetrics: make(map[string]engine.StatMetric), + } + for _, metricID := range sqp.Metrics { + if metric, err := engine.NewStatMetric(metricID, 0); err != nil { + t.Error("Error when creating newstatMETRIc ", err.Error()) + } else { + sq.SQMetrics[metricID] = metric + } + } + switch { + case dbtype == utils.REDIS: + + err := mig.oldDataDB.setV1Stats(v1Sts) + if err != nil { + t.Error("Error when setting v1Stat ", err.Error()) + } + currentVersion := engine.Versions{utils.StatS: 1, utils.Thresholds: 1, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dm.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaStats}) + if err != nil { + t.Error("Error when migrating Stats ", err.Error()) + } + + result, err := mig.dm.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + + if !reflect.DeepEqual(sqp.Tenant, result.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Tenant, result.Tenant) + } + if !reflect.DeepEqual(sqp.ID, result.ID) { + t.Errorf("Expecting: %+v, received: %+v", sqp.ID, result.ID) + } + if !reflect.DeepEqual(sqp.FilterIDs, result.FilterIDs) { + t.Errorf("Expecting: %+v, received: %+v", sqp.FilterIDs, result.FilterIDs) + } + if !reflect.DeepEqual(sqp.QueueLength, result.QueueLength) { + t.Errorf("Expecting: %+v, received: %+v", sqp.QueueLength, result.QueueLength) + } + if !reflect.DeepEqual(sqp.TTL, result.TTL) { + t.Errorf("Expecting: %+v, received: %+v", sqp.TTL, result.TTL) + } + if !reflect.DeepEqual(sqp.Metrics, result.Metrics) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Metrics, result.Metrics) + } + if !reflect.DeepEqual(sqp.Thresholds, result.Thresholds) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Thresholds, result.Thresholds) + } + if !reflect.DeepEqual(sqp.Blocker, result.Blocker) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Blocker, result.Blocker) + } + if !reflect.DeepEqual(sqp.Stored, result.Stored) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Stored, result.Stored) + } + if !reflect.DeepEqual(sqp.Weight, result.Weight) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Weight, result.Weight) + } + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) + } + result1, err := mig.dm.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(filter, result1) { + t.Errorf("Expecting: %+v, received: %+v", filter, result1) + } + + case dbtype == utils.MONGO: + err := mig.oldDataDB.setV1Stats(v1Sts) + if err != nil { + t.Error("Error when setting v1Stat ", err.Error()) + } + currentVersion := engine.Versions{utils.StatS: 1, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dm.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaStats}) + if err != nil { + t.Error("Error when migrating Stats ", err.Error()) + } + result, err := mig.dm.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(sqp.Tenant, result.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Tenant, result.Tenant) + } + if !reflect.DeepEqual(sqp.ID, result.ID) { + t.Errorf("Expecting: %+v, received: %+v", sqp.ID, result.ID) + } + if !reflect.DeepEqual(sqp.FilterIDs, result.FilterIDs) { + t.Errorf("Expecting: %+v, received: %+v", sqp.FilterIDs, result.FilterIDs) + } + if !reflect.DeepEqual(sqp.QueueLength, result.QueueLength) { + t.Errorf("Expecting: %+v, received: %+v", sqp.QueueLength, result.QueueLength) + } + if !reflect.DeepEqual(sqp.TTL, result.TTL) { + t.Errorf("Expecting: %+v, received: %+v", sqp.TTL, result.TTL) + } + if !reflect.DeepEqual(sqp.Metrics, result.Metrics) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Metrics, result.Metrics) + } + if !reflect.DeepEqual(sqp.Thresholds, result.Thresholds) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Thresholds, result.Thresholds) + } + if !reflect.DeepEqual(sqp.Blocker, result.Blocker) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Blocker, result.Blocker) + } + if !reflect.DeepEqual(sqp.Stored, result.Stored) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Stored, result.Stored) + } + if !reflect.DeepEqual(sqp.Weight, result.Weight) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Weight, result.Weight) + } + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) + } + result1, err := mig.dm.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(filter.ActivationInterval, result1.ActivationInterval) { + t.Errorf("Expecting: %+v, received: %+v", filter.ActivationInterval, result1.ActivationInterval) + } + if !reflect.DeepEqual(filter.Tenant, result1.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", filter.Tenant, result1.Tenant) + } + } + result1, err := mig.dm.GetStatQueue("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + log.Print("Wrong version", result1) + +} diff --git a/migrator/stats.go b/migrator/stats.go new file mode 100644 index 000000000..aad3c4e86 --- /dev/null +++ b/migrator/stats.go @@ -0,0 +1,313 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type v1Stat struct { + Id string // Config id, unique per config instance + QueueLength int // Number of items in the stats buffer + TimeWindow time.Duration // Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow + SaveInterval time.Duration + Metrics []string // ASR, ACD, ACC + SetupInterval []time.Time // CDRFieldFilter on SetupInterval, 2 or less items (>= start interval,< stop_interval) + TOR []string // CDRFieldFilter on TORs + CdrHost []string // CDRFieldFilter on CdrHosts + CdrSource []string // CDRFieldFilter on CdrSources + ReqType []string // CDRFieldFilter on RequestTypes + Direction []string // CDRFieldFilter on Directions + Tenant []string // CDRFieldFilter on Tenants + Category []string // CDRFieldFilter on Categories + Account []string // CDRFieldFilter on Accounts + Subject []string // CDRFieldFilter on Subjects + DestinationIds []string // CDRFieldFilter on DestinationPrefixes + UsageInterval []time.Duration // CDRFieldFilter on UsageInterval, 2 or less items (>= Usage, = Pdd, =Cost, when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for Stats model") + } + if vrs[utils.StatS] != 1 { // Right now we only support migrating from version 1 + log.Print("Wrong version") + return + } + var v1Sts *v1Stat + for { + v1Sts, err = m.oldDataDB.getV1Stats() + if err != nil && err != utils.ErrNoMoreData { + return err + } + if err == utils.ErrNoMoreData { + break + } + if v1Sts.Id != "" { + if len(v1Sts.Triggers) != 0 { + for _, Trigger := range v1Sts.Triggers { + if err := m.SasThreshold(Trigger); err != nil { + return err + + } + } + } + filter, sq, sts, err := v1Sts.AsStatQP() + if err != nil { + return err + } + if m.dryRun != true { + if err := m.dm.SetFilter(filter); err != nil { + return err + } + if err := m.dm.SetStatQueue(sq); err != nil { + return err + } + if err := m.dm.SetStatQueueProfile(sts); err != nil { + return err + } + m.stats[utils.StatS] += 1 + } + } + } + if m.dryRun != true { + // All done, update version wtih current one + vrs := engine.Versions{utils.StatS: engine.CurrentStorDBVersions()[utils.StatS]} + if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when updating Stats version into dataDB", err.Error())) + } + } + return +} + +func (v1Sts v1Stat) AsStatQP() (filter *engine.Filter, sq *engine.StatQueue, stq *engine.StatQueueProfile, err error) { + var filters []*engine.RequestFilter + if len(v1Sts.SetupInterval) == 1 { + x, err := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "SetupInterval", []string{v1Sts.SetupInterval[0].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } else if len(v1Sts.SetupInterval) == 2 { + x, err := engine.NewRequestFilter(engine.MetaLessThan, "SetupInterval", []string{v1Sts.SetupInterval[1].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + + if len(v1Sts.TOR) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "TOR", v1Sts.TOR) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.CdrHost) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "CdrHost", v1Sts.CdrHost) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.ReqType) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "ReqType", v1Sts.ReqType) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Direction) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Direction", v1Sts.Direction) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Category) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Category", v1Sts.Category) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Account) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Account", v1Sts.Account) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Subject) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Subject", v1Sts.Subject) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Supplier) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Supplier", v1Sts.Supplier) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.UsageInterval) == 1 { + x, err := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "UsageInterval", []string{v1Sts.UsageInterval[0].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } else if len(v1Sts.UsageInterval) == 2 { + x, err := engine.NewRequestFilter(engine.MetaLessThan, "UsageInterval", []string{v1Sts.UsageInterval[1].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.PddInterval) == 1 { + x, err := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "PddInterval", []string{v1Sts.PddInterval[0].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } else if len(v1Sts.PddInterval) == 2 { + x, err := engine.NewRequestFilter(engine.MetaLessThan, "PddInterval", []string{v1Sts.PddInterval[1].String()}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.Supplier) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Supplier", v1Sts.Supplier) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.DisconnectCause) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "DisconnectCause", v1Sts.DisconnectCause) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.MediationRunIds) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "MediationRunIds", v1Sts.MediationRunIds) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.RatedSubject) != 0 { + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "RatedSubject", v1Sts.RatedSubject) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if len(v1Sts.CostInterval) == 1 { + x, err := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "CostInterval", []string{strconv.FormatFloat(v1Sts.CostInterval[0], 'f', 6, 64)}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } else if len(v1Sts.CostInterval) == 2 { + x, err := engine.NewRequestFilter(engine.MetaLessThan, "CostInterval", []string{strconv.FormatFloat(v1Sts.CostInterval[1], 'f', 6, 64)}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + filter = &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: v1Sts.Id, RequestFilters: filters} + stq = &engine.StatQueueProfile{ + ID: v1Sts.Id, + QueueLength: v1Sts.QueueLength, + Metrics: []string{}, + Tenant: config.CgrConfig().DefaultTenant, + Blocker: false, + Stored: false, + Thresholds: []string{}, + FilterIDs: []string{v1Sts.Id}, + } + if v1Sts.SaveInterval != 0 { + stq.Stored = true + } + if len(v1Sts.Triggers) != 0 { + for i, _ := range v1Sts.Triggers { + stq.Thresholds = append(stq.Thresholds, v1Sts.Triggers[i].ID) + } + } + sq = &engine.StatQueue{Tenant: config.CgrConfig().DefaultTenant, + ID: v1Sts.Id, + SQMetrics: make(map[string]engine.StatMetric), + } + if len(v1Sts.Metrics) != 0 { + for i, _ := range v1Sts.Metrics { + if !strings.HasPrefix(v1Sts.Metrics[i], "*") { + v1Sts.Metrics[i] = "*" + v1Sts.Metrics[i] + } + v1Sts.Metrics[i] = strings.ToLower(v1Sts.Metrics[i]) + stq.Metrics = append(stq.Metrics, v1Sts.Metrics[i]) + if metric, err := engine.NewStatMetric(stq.Metrics[i], 0); err != nil { + return nil, nil, nil, err + } else { + sq.SQMetrics[stq.Metrics[i]] = metric + } + } + } + return filter, sq, stq, nil +} diff --git a/migrator/stats_test.go b/migrator/stats_test.go new file mode 100644 index 000000000..44348841c --- /dev/null +++ b/migrator/stats_test.go @@ -0,0 +1,139 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package migrator + +import ( + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func TestV1StatsAsStats(t *testing.T) { + tim := time.Date(0001, time.January, 1, 2, 0, 0, 0, time.UTC).Local() + var filters []*engine.RequestFilter + v1Sts := &v1Stat{ + Id: "test", // Config id, unique per config instance + QueueLength: 10, // Number of items in the stats buffer + TimeWindow: time.Duration(1) * time.Second, // Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow + SaveInterval: time.Duration(1) * time.Second, + Metrics: []string{"ASR", "ACD", "ACC"}, + SetupInterval: []time.Time{time.Now()}, + TOR: []string{}, + CdrHost: []string{}, + CdrSource: []string{}, + ReqType: []string{}, + Direction: []string{}, + Tenant: []string{}, + Category: []string{}, + Account: []string{}, + Subject: []string{}, + DestinationIds: []string{}, + UsageInterval: []time.Duration{1 * time.Second}, + PddInterval: []time.Duration{1 * time.Second}, + Supplier: []string{}, + DisconnectCause: []string{}, + MediationRunIds: []string{}, + RatedAccount: []string{}, + RatedSubject: []string{}, + CostInterval: []float64{}, + Triggers: engine.ActionTriggers{&engine.ActionTrigger{ + ID: "TestB", + Balance: &engine.BalanceFilter{ + ID: utils.StringPointer("TESTB"), + Timings: []*engine.RITiming{}, + ExpirationDate: utils.TimePointer(tim), + Type: utils.StringPointer(utils.MONETARY), + Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), + }, + ExpirationDate: tim, + LastExecutionTime: tim, + ActivationDate: tim, + ThresholdType: utils.TRIGGER_MAX_BALANCE, + ThresholdValue: 2, + ActionsID: "TEST_ACTIONS", + Executed: true, + }}, + } + + x, _ := engine.NewRequestFilter(engine.MetaGreaterOrEqual, "SetupInterval", []string{v1Sts.SetupInterval[0].String()}) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaGreaterOrEqual, "UsageInterval", []string{v1Sts.UsageInterval[0].String()}) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaGreaterOrEqual, "PddInterval", []string{v1Sts.PddInterval[0].String()}) + filters = append(filters, x) + + filter := &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: v1Sts.Id, RequestFilters: filters} + + sqp := &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "test", + FilterIDs: []string{v1Sts.Id}, + QueueLength: 10, + TTL: time.Duration(0) * time.Second, + Metrics: []string{"*asr", "*acd", "*acc"}, + Blocker: false, + Thresholds: []string{"TestB"}, + Stored: true, + Weight: float64(0), + MinItems: 0, + } + fltr, _, newsqp, err := v1Sts.AsStatQP() + if err != nil { + t.Errorf("err") + } + if !reflect.DeepEqual(sqp.Tenant, newsqp.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Tenant, newsqp.Tenant) + } + if !reflect.DeepEqual(sqp.ID, newsqp.ID) { + t.Errorf("Expecting: %+v, received: %+v", sqp.ID, newsqp.ID) + } + if !reflect.DeepEqual(sqp.FilterIDs, newsqp.FilterIDs) { + t.Errorf("Expecting: %+v, received: %+v", sqp.FilterIDs, newsqp.FilterIDs) + } + if !reflect.DeepEqual(sqp.QueueLength, newsqp.QueueLength) { + t.Errorf("Expecting: %+v, received: %+v", sqp.QueueLength, newsqp.QueueLength) + } + if !reflect.DeepEqual(sqp.TTL, newsqp.TTL) { + t.Errorf("Expecting: %+v, received: %+v", sqp.TTL, newsqp.TTL) + } + if !reflect.DeepEqual(sqp.Metrics, newsqp.Metrics) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Metrics, newsqp.Metrics) + } + if !reflect.DeepEqual(sqp.Thresholds, newsqp.Thresholds) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Thresholds, newsqp.Thresholds) + } + if !reflect.DeepEqual(sqp.Blocker, newsqp.Blocker) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Blocker, newsqp.Blocker) + } + if !reflect.DeepEqual(sqp.Stored, newsqp.Stored) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Stored, newsqp.Stored) + } + if !reflect.DeepEqual(sqp.Weight, newsqp.Weight) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Weight, newsqp.Weight) + } + if !reflect.DeepEqual(sqp, newsqp) { + t.Errorf("Expecting: %+v, received: %+v", sqp, newsqp) + } + if !reflect.DeepEqual(filter, fltr) { + t.Errorf("Expecting: %+v, received: %+v", filter, fltr) + } +} diff --git a/migrator/thresholds.go b/migrator/thresholds.go new file mode 100644 index 000000000..d7be759c3 --- /dev/null +++ b/migrator/thresholds.go @@ -0,0 +1,296 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "log" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type v2ActionTrigger struct { + ID string // original csv tag + UniqueID string // individual id + ThresholdType string //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *balance_expired + // stats: *min_asr, *max_asr, *min_acd, *max_acd, *min_tcd, *max_tcd, *min_acc, *max_acc, *min_tcc, *max_tcc, *min_ddc, *max_ddc + ThresholdValue float64 + Recurrent bool // reset excuted flag each run + MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers + ExpirationDate time.Time + ActivationDate time.Time + //BalanceType string // *monetary/*voice etc + Balance *engine.BalanceFilter //filtru + Weight float64 + ActionsID string + MinQueuedItems int // Trigger actions only if this number is hit (stats only) MINHITS + Executed bool + LastExecutionTime time.Time +} + +type v2ActionTriggers []*v2ActionTrigger + +func (m *Migrator) migratev1ActionTriggers() (err error) { + var vrs engine.Versions + if m.dm.DataDB() == nil { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.NoStorDBConnection, + "no connection to datadb") + } + vrs, err = m.dm.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for Stats model") + } + if vrs[utils.Thresholds] != 1 { // Right now we only support migrating from version 1 + log.Print("Wrong version") + return + } + var v2ACT *v2ActionTrigger + for { + v2ACT, err = m.oldDataDB.getV2ActionTrigger() + if err != nil && err != utils.ErrNoMoreData { + return err + } + if err == utils.ErrNoMoreData { + break + } + if v2ACT.ID != "" { + thp, th, filter, err := v2ACT.AsThreshold() + if err != nil { + return err + } + if m.dryRun != true { + if err := m.dm.SetFilter(filter); err != nil { + return err + } + if err := m.dm.SetThreshold(th); err != nil { + return err + } + if err := m.dm.SetThresholdProfile(thp); err != nil { + return err + } + m.stats[utils.Thresholds] += 1 + } + } + } + if m.dryRun != true { + // All done, update version wtih current one + vrs := engine.Versions{utils.Thresholds: engine.CurrentStorDBVersions()[utils.Thresholds]} + if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when updating Thresholds version into dataDB", err.Error())) + } + } + return +} +func (v2ATR v2ActionTrigger) AsThreshold() (thp *engine.ThresholdProfile, th *engine.Threshold, filter *engine.Filter, err error) { + var filters []*engine.RequestFilter + if *v2ATR.Balance.ID != "" { + if v2ATR.Balance.Directions != nil { + x, err := engine.NewRequestFilter(engine.MetaRSRFields, "Directions", v2ATR.Balance.Directions.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + //TO DO: + // if v2ATR.Balance.ExpirationDate != nil { //MetaLess + // x, err := engine.NewRequestFilter(engine.MetaTimings, "ExpirationDate", v2ATR.Balance.ExpirationDate) + // if err != nil { + // return nil, nil, err + // } + // filters = append(filters, x) + // } + // if v2ATR.Balance.Weight != nil { //MetaLess /MetaRSRFields + // x, err := engine.NewRequestFilter(engine.MetaLessOrEqual, "Weight", []string{strconv.FormatFloat(*v2ATR.Balance.Weight, 'f', 6, 64)}) + // if err != nil { + // return nil, nil, err + // } + // filters = append(filters, x) + // } + if v2ATR.Balance.DestinationIDs != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaDestinations, "DestinationIDs", v2ATR.Balance.DestinationIDs.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.RatingSubject != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "RatingSubject", []string{*v2ATR.Balance.RatingSubject}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.Categories != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Categories", v2ATR.Balance.Categories.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.SharedGroups != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "SharedGroups", v2ATR.Balance.SharedGroups.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.TimingIDs != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "TimingIDs", v2ATR.Balance.TimingIDs.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + } + filter = &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: *v2ATR.Balance.ID, RequestFilters: filters} + + th = &engine.Threshold{ + Tenant: config.CgrConfig().DefaultTenant, + ID: v2ATR.ID, + } + + thp = &engine.ThresholdProfile{ + ID: v2ATR.ID, + Tenant: config.CgrConfig().DefaultTenant, + Weight: v2ATR.Weight, + ActivationInterval: &utils.ActivationInterval{ActivationTime: v2ATR.ActivationDate, ExpiryTime: v2ATR.ExpirationDate}, + FilterIDs: []string{filter.ID}, + MinSleep: v2ATR.MinSleep, + } + return thp, th, filter, nil +} + +func (m *Migrator) SasThreshold(v2ATR *engine.ActionTrigger) (err error) { + var vrs engine.Versions + if m.dm.DataDB() == nil { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.NoStorDBConnection, + "no connection to datadb") + } + if v2ATR.ID != "" { + thp, th, filter, err := AsThreshold2(*v2ATR) + if err != nil { + return err + } + if filter != nil { + if err := m.dm.SetFilter(filter); err != nil { + return err + } + } + if err := m.dm.SetThreshold(th); err != nil { + return err + } + if err := m.dm.SetThresholdProfile(thp); err != nil { + return err + } + m.stats[utils.Thresholds] += 1 + } + // All done, update version wtih current one + vrs = engine.Versions{utils.Thresholds: engine.CurrentStorDBVersions()[utils.Thresholds]} + if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when updating Thresholds version into dataDB", err.Error())) + } + return +} + +func AsThreshold2(v2ATR engine.ActionTrigger) (thp *engine.ThresholdProfile, th *engine.Threshold, filter *engine.Filter, err error) { + var filterIDS []string + var filters []*engine.RequestFilter + if v2ATR.Balance.ID != nil && *v2ATR.Balance.ID != "" { + if v2ATR.Balance.Directions != nil { + x, err := engine.NewRequestFilter(engine.MetaRSRFields, "Directions", v2ATR.Balance.Directions.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.DestinationIDs != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaDestinations, "DestinationIDs", v2ATR.Balance.DestinationIDs.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.RatingSubject != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "RatingSubject", []string{*v2ATR.Balance.RatingSubject}) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.Categories != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "Categories", v2ATR.Balance.Categories.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.SharedGroups != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "SharedGroups", v2ATR.Balance.SharedGroups.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + if v2ATR.Balance.TimingIDs != nil { //MetaLess /RSRfields + x, err := engine.NewRequestFilter(engine.MetaStringPrefix, "TimingIDs", v2ATR.Balance.TimingIDs.Slice()) + if err != nil { + return nil, nil, nil, err + } + filters = append(filters, x) + } + filter = &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: *v2ATR.Balance.ID, RequestFilters: filters} + filterIDS = append(filterIDS, filter.ID) + } + th = &engine.Threshold{ + Tenant: config.CgrConfig().DefaultTenant, + ID: v2ATR.ID, + } + + thp = &engine.ThresholdProfile{ + ID: v2ATR.ID, + Tenant: config.CgrConfig().DefaultTenant, + Weight: v2ATR.Weight, + ActivationInterval: &utils.ActivationInterval{ActivationTime: v2ATR.ActivationDate, ExpiryTime: v2ATR.ExpirationDate}, + FilterIDs: filterIDS, + MinSleep: v2ATR.MinSleep, + } + + return thp, th, filter, nil +} diff --git a/migrator/thresholds_test.go b/migrator/thresholds_test.go new file mode 100644 index 000000000..1cfdb5d2d --- /dev/null +++ b/migrator/thresholds_test.go @@ -0,0 +1,89 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package migrator + +import ( + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func Testv2ActionTriggerAsThreshold(t *testing.T) { + var filters []*engine.RequestFilter + v2ATR := &v2ActionTrigger{ + ID: "test2", // original csv tag + UniqueID: "testUUID", // individual id + ThresholdType: "*min_event_counter", //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *balance_expired + ThresholdValue: 5.32, + Recurrent: false, // reset excuted flag each run + MinSleep: time.Duration(5) * time.Second, // Minimum duration between two executions in case of recurrent triggers + ExpirationDate: time.Now(), + ActivationDate: time.Now(), + Balance: new(engine.BalanceFilter), + Weight: 0, + ActionsID: "Action1", + MinQueuedItems: 10, // Trigger actions only if this number is hit (stats only) + Executed: false, + LastExecutionTime: time.Now(), + } + x, _ := engine.NewRequestFilter(engine.MetaRSRFields, "Directions", v2ATR.Balance.Directions.Slice()) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaDestinations, "DestinationIDs", v2ATR.Balance.DestinationIDs.Slice()) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaStringPrefix, "RatingSubject", []string{*v2ATR.Balance.RatingSubject}) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaStringPrefix, "Categories", v2ATR.Balance.Categories.Slice()) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaStringPrefix, "SharedGroups", v2ATR.Balance.SharedGroups.Slice()) + filters = append(filters, x) + x, _ = engine.NewRequestFilter(engine.MetaStringPrefix, "TimingIDs", v2ATR.Balance.TimingIDs.Slice()) + filters = append(filters, x) + + filter := &engine.Filter{Tenant: config.CgrConfig().DefaultTenant, ID: *v2ATR.Balance.ID, RequestFilters: filters} + + thp := &engine.ThresholdProfile{ + ID: v2ATR.ID, + Tenant: config.CgrConfig().DefaultTenant, + Blocker: false, + Weight: v2ATR.Weight, + ActivationInterval: &utils.ActivationInterval{v2ATR.ExpirationDate, v2ATR.ActivationDate}, + MinSleep: v2ATR.MinSleep, + } + th := &engine.Threshold{ + Tenant: config.CgrConfig().DefaultTenant, + ID: v2ATR.ID, + } + + newthp, newth, fltr, err := v2ATR.AsThreshold() + if err != nil { + t.Errorf("err") + } + if !reflect.DeepEqual(thp, newthp) { + t.Errorf("Expecting: %+v, received: %+v", thp, newthp) + } + if !reflect.DeepEqual(th, newth) { + t.Errorf("Expecting: %+v, received: %+v", th, newth) + } + if !reflect.DeepEqual(filter, fltr) { + t.Errorf("Expecting: %+v, received: %+v", filter, fltr) + } +} diff --git a/migrator/v1datadb.go b/migrator/v1datadb.go index 57f6eebd1..9719472fd 100644 --- a/migrator/v1datadb.go +++ b/migrator/v1datadb.go @@ -30,4 +30,8 @@ type V1DataDB interface { setV1ActionTriggers(x *v1ActionTriggers) (err error) getV1SharedGroup() (v1acts *v1SharedGroup, err error) setV1SharedGroup(x *v1SharedGroup) (err error) + getV1Stats() (v1st *v1Stat, err error) + setV1Stats(x *v1Stat) (err error) + getV2ActionTrigger() (v2at *v2ActionTrigger, err error) + setV2ActionTrigger(x *v2ActionTrigger) (err error) } diff --git a/migrator/v1mongo_data.go b/migrator/v1mongo_data.go index ccb6900d2..ba0d7b26e 100644 --- a/migrator/v1mongo_data.go +++ b/migrator/v1mongo_data.go @@ -174,3 +174,49 @@ func (v1ms *v1Mongo) setV1SharedGroup(x *v1SharedGroup) (err error) { } return } + +//Stats methods +//get +func (v1ms *v1Mongo) getV1Stats() (v1st *v1Stat, err error) { + if v1ms.qryIter == nil { + v1ms.qryIter = v1ms.session.DB(v1ms.db).C(utils.CDR_STATS_PREFIX).Find(nil).Iter() + } + v1ms.qryIter.Next(&v1st) + if v1st == nil { + v1ms.qryIter = nil + return nil, utils.ErrNoMoreData + + } + return v1st, nil +} + +//set +func (v1ms *v1Mongo) setV1Stats(x *v1Stat) (err error) { + if err := v1ms.session.DB(v1ms.db).C(utils.CDR_STATS_PREFIX).Insert(x); err != nil { + return err + } + return +} + +//Stats methods +//get +func (v1ms *v1Mongo) getV2ActionTrigger() (v2at *v2ActionTrigger, err error) { + if v1ms.qryIter == nil { + v1ms.qryIter = v1ms.session.DB(v1ms.db).C(utils.ACTION_TRIGGER_PREFIX).Find(nil).Iter() + } + v1ms.qryIter.Next(&v2at) + if v2at == nil { + v1ms.qryIter = nil + return nil, utils.ErrNoMoreData + + } + return v2at, nil +} + +//set +func (v1ms *v1Mongo) setV2ActionTrigger(x *v2ActionTrigger) (err error) { + if err := v1ms.session.DB(v1ms.db).C(utils.ACTION_TRIGGER_PREFIX).Insert(x); err != nil { + return err + } + return +} diff --git a/migrator/v1redis.go b/migrator/v1redis.go index 5780193b5..d4764b226 100644 --- a/migrator/v1redis.go +++ b/migrator/v1redis.go @@ -20,6 +20,7 @@ package migrator import ( "fmt" + "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -305,3 +306,85 @@ func (v1rs *v1Redis) setV1SharedGroup(x *v1SharedGroup) (err error) { } return } + +//Stats methods +//get +func (v1rs *v1Redis) getV1Stats() (v1st *v1Stat, err error) { + if v1rs.qryIdx == nil { + v1rs.dataKeys, err = v1rs.getKeysForPrefix(utils.CDR_STATS_PREFIX) + if err != nil { + return + } else if len(v1rs.dataKeys) == 0 { + return nil, utils.ErrNotFound + } + v1rs.qryIdx = utils.IntPointer(0) + } + if *v1rs.qryIdx <= len(v1rs.dataKeys)-1 { + strVal, err := v1rs.cmd("GET", v1rs.dataKeys[*v1rs.qryIdx]).Bytes() + if err != nil { + return nil, err + } + if err := v1rs.ms.Unmarshal(strVal, &v1st); err != nil { + return nil, err + } + *v1rs.qryIdx = *v1rs.qryIdx + 1 + } else { + v1rs.qryIdx = nil + return nil, utils.ErrNoMoreData + } + return v1st, nil +} + +//set +func (v1rs *v1Redis) setV1Stats(x *v1Stat) (err error) { + key := utils.CDR_STATS_PREFIX + x.Id + bit, err := v1rs.ms.Marshal(x) + if err != nil { + return err + } + if err = v1rs.cmd("SET", key, bit).Err; err != nil { + return err + } + return +} + +//Action methods +//get +func (v1rs *v1Redis) getV2ActionTrigger() (v2at *v2ActionTrigger, err error) { + if v1rs.qryIdx == nil { + v1rs.dataKeys, err = v1rs.getKeysForPrefix(utils.ACTION_TRIGGER_PREFIX) + if err != nil { + return + } else if len(v1rs.dataKeys) == 0 { + return nil, utils.ErrNotFound + } + v1rs.qryIdx = utils.IntPointer(0) + } + if *v1rs.qryIdx <= len(v1rs.dataKeys)-1 { + strVal, err := v1rs.cmd("GET", v1rs.dataKeys[*v1rs.qryIdx]).Bytes() + if err != nil { + return nil, err + } + if err := v1rs.ms.Unmarshal(strVal, &v2at); err != nil { + return nil, err + } + *v1rs.qryIdx = *v1rs.qryIdx + 1 + } else { + v1rs.qryIdx = nil + return nil, utils.ErrNoMoreData + } + return v2at, nil +} + +//set +func (v1rs *v1Redis) setV2ActionTrigger(x *v2ActionTrigger) (err error) { + key := utils.ACTION_TRIGGER_PREFIX + x.ID + bit, err := v1rs.ms.Marshal(x) + if err != nil { + return err + } + if err = v1rs.cmd("SET", key, bit).Err; err != nil { + return err + } + return +} diff --git a/utils/consts.go b/utils/consts.go index 1484d5845..22e56ed5b 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -397,6 +397,8 @@ const ( MetaActionTriggers = "*action_triggers" MetaActions = "*actions" MetaSharedGroups = "*shared_groups" + MetaStats = "*stats" + MetaThresholds = "*thresholds" Migrator = "migrator" UnsupportedMigrationTask = "unsupported migration task" NoStorDBConnection = "not connected to StorDB" @@ -450,6 +452,7 @@ const ( CacheResources = "resources" CacheResourceProfiles = "resource_profiles" CacheTimings = "timings" + Thresholds = "Thresholds" StatS = "stats" StatService = "StatS" RALService = "RALs" From 27420bdd806914b67229e6cbfcb4ee9fb2fc7862 Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Tue, 7 Nov 2017 12:24:33 +0000 Subject: [PATCH 35/75] Added migration from action triggers to thresholds and cdrstats to stats --- engine/version.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/engine/version.go b/engine/version.go index f364f8c3f..ec7d7ffb8 100644 --- a/engine/version.go +++ b/engine/version.go @@ -104,15 +104,6 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } -func CurrentStorDBVersions() Versions { - return Versions{utils.COST_DETAILS: 2, utils.CDRs: 2} -} - -func CurrentDataDBVersions() Versions { - return Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, - utils.ActionPlans: 2, utils.SharedGroups: 2} -} - func CurrentDBVersions(storType string) Versions { dataDbVersions := CurrentDataDBVersions() storDbVersions := CurrentStorDBVersions() @@ -136,5 +127,13 @@ func CurrentDBVersions(storType string) Versions { return nil } +func CurrentDataDBVersions() Versions { + return Versions{utils.StatS: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.Thresholds: 2} +} + +func CurrentStorDBVersions() Versions { + return Versions{utils.COST_DETAILS: 2} +} + // Versions will keep trac of various item versions type Versions map[string]int64 // map[item]versionNr From 6b8f84ed0a84920a2504b7a98d917478a51e464b Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 7 Nov 2017 18:04:38 +0200 Subject: [PATCH 36/75] Add new format for time "+24h" --- utils/coreutils.go | 8 ++++++++ utils/coreutils_test.go | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/utils/coreutils.go b/utils/coreutils.go index eef7f5b65..cfe658a4f 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -205,6 +205,14 @@ func ParseTimeDetectLayout(tmStr string, timezone string) (time.Time, error) { return time.ParseInLocation("20060102150405.999", tmStr, loc) case tmStr == "*now": return time.Now(), nil + case strings.HasPrefix(tmStr, "+"): + tmStr = strings.TrimPrefix(tmStr, "+") + if tmStrTmp, err := time.ParseDuration(tmStr); err != nil { + return nilTime, err + } else { + return time.Now().Add(tmStrTmp), nil + } + } return nilTime, errors.New("Unsupported time format") } diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index deb86cbd6..b3e481f1f 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -214,6 +214,15 @@ func TestParseTimeDetectLayout(t *testing.T) { } else if !astTMS.Equal(expectedTime) { t.Errorf("Expecting: %v, received: %v", expectedTime, astTMS) } + nowTimeStr := "+24h" + start := time.Now().Add(time.Duration(23*time.Hour + 59*time.Minute + 58*time.Second)) + end := start.Add(time.Duration(2 * time.Second)) + parseNowTimeStr, err := ParseTimeDetectLayout(nowTimeStr, "") + if err != nil { + t.Error(err) + } else if parseNowTimeStr.After(start) && parseNowTimeStr.Before(end) { + t.Errorf("Unexpected time parsed: %v", parseNowTimeStr) + } } func TestParseDateUnix(t *testing.T) { From 7d82717aacc21b593294eae031e5598d1315513b Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 8 Nov 2017 14:46:41 +0200 Subject: [PATCH 37/75] Add test for ApierV1.RemoveAccount in general_tests and update method --- apier/v1/accounts.go | 7 +- general_tests/accounts_it_test.go | 160 ++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 general_tests/accounts_it_test.go diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index f21265c7a..a152d6cda 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -339,10 +339,11 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) return utils.NewErrServerError(err) } if err = self.DataManager.DataDB().RemAccountActionPlans(accID, nil); err != nil { - return + return err } - if err = self.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{accID}, true); err != nil { - return + + if err = self.DataManager.CacheDataFromDB(utils.AccountActionPlansPrefix, []string{accID}, true); err.Error() != utils.ErrNotFound.Error() { + return err } *reply = OK return nil diff --git a/general_tests/accounts_it_test.go b/general_tests/accounts_it_test.go new file mode 100644 index 000000000..505382f2c --- /dev/null +++ b/general_tests/accounts_it_test.go @@ -0,0 +1,160 @@ +// +build integration + +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package general_tests + +import ( + "net/rpc" + "net/rpc/jsonrpc" + "path" + //"reflect" + "testing" + "time" + + //"github.com/cgrates/cgrates/apier/v2" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +var ( + accCfgPath string + accCfg *config.CGRConfig + accRpc *rpc.Client + accConfDIR string //run tests for specific configuration + account *engine.Account + accDelay int +) + +var sTestsAcc = []func(t *testing.T){ + testV1AccLoadConfig, + testV1AccInitDataDb, + testAccResetStorDb, + testV1AccStartEngine, + testV1AccRpcConn, + testV1AccGetAccountBeforeSet, + testV1AccLoadTarrifPlans, + testV1AccGetAccountAfterLoad, + testV1AccRemAccount, + testV1AccGetAccountAfterDelete, + testV1AccStopEngine, +} + +// Test start here +func TestAccITMySQL(t *testing.T) { + accConfDIR = "tutmysql" + for _, stest := range sTestsAcc { + t.Run(accConfDIR, stest) + } +} + +func TestAccITMongo(t *testing.T) { + accConfDIR = "tutmongo" + for _, stest := range sTestsAcc { + t.Run(accConfDIR, stest) + } +} + +func testV1AccLoadConfig(t *testing.T) { + var err error + accCfgPath = path.Join(*dataDir, "conf", "samples", accConfDIR) + if accCfg, err = config.NewCGRConfigFromFolder(accCfgPath); err != nil { + t.Error(err) + } + switch accConfDIR { + case "tutmongo": // Mongo needs more time to reset db, need to investigate + accDelay = 2000 + default: + accDelay = 1000 + } +} + +func testV1AccInitDataDb(t *testing.T) { + if err := engine.InitDataDb(accCfg); err != nil { + t.Fatal(err) + } +} + +func testAccResetStorDb(t *testing.T) { + if err := engine.InitStorDb(accCfg); err != nil { + t.Fatal(err) + } +} + +func testV1AccStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(accCfgPath, accDelay); err != nil { + t.Fatal(err) + } +} + +func testV1AccRpcConn(t *testing.T) { + var err error + accRpc, err = jsonrpc.Dial("tcp", accCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } +} + +func testV1AccGetAccountBeforeSet(t *testing.T) { + var reply *engine.Account + if err := accRpc.Call("ApierV2.GetAccount", &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testV1AccLoadTarrifPlans(t *testing.T) { + var reply string + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")} + if err := accRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned", reply) + } + time.Sleep(500 * time.Millisecond) +} + +func testV1AccGetAccountAfterLoad(t *testing.T) { + var reply *engine.Account + if err := accRpc.Call("ApierV2.GetAccount", &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}, &reply); err != nil { + t.Error(err) + } +} + +func testV1AccRemAccount(t *testing.T) { + var reply string + if err := accRpc.Call("ApierV1.RemoveAccount", &utils.AttrRemoveAccount{Tenant: "cgrates.org", Account: "1001"}, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned", reply) + } + +} + +func testV1AccGetAccountAfterDelete(t *testing.T) { + var reply *engine.Account + if err := accRpc.Call("ApierV2.GetAccount", &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testV1AccStopEngine(t *testing.T) { + if err := engine.KillEngine(accDelay); err != nil { + t.Error(err) + } +} From bdbabf3a244a9c77ade66a6571bd8c86988640e2 Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 8 Nov 2017 16:00:58 +0200 Subject: [PATCH 38/75] Caching StatQueueProfile and StatQueue and upadte tests --- apier/v1/smgenericv1_it_test.go | 4 +- engine/datamanager.go | 6 + engine/onstor_it_test.go | 199 ++++++++++++++++++++++++- engine/storage_redis.go | 3 +- general_tests/tut_smgeneric_it_test.go | 4 +- general_tests/tutorial_it_test.go | 4 +- 6 files changed, 211 insertions(+), 9 deletions(-) diff --git a/apier/v1/smgenericv1_it_test.go b/apier/v1/smgenericv1_it_test.go index eb008ebaa..52b58d0fa 100644 --- a/apier/v1/smgenericv1_it_test.go +++ b/apier/v1/smgenericv1_it_test.go @@ -102,8 +102,8 @@ func TestSMGV1CacheStats(t *testing.T) { var rcvStats *utils.CacheStats expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, - LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, - StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} var args utils.AttrCacheStats if err := smgV1Rpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) diff --git a/engine/datamanager.go b/engine/datamanager.go index ba2f2370f..bc42d3ad1 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -203,6 +203,12 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b case utils.ResourcesPrefix: tntID := utils.NewTenantID(dataID) _, err = dm.GetResource(tntID.Tenant, tntID.ID, true, utils.NonTransactional) + case utils.StatQueueProfilePrefix: + tntID := utils.NewTenantID(dataID) + _, err = dm.GetStatQueueProfile(tntID.Tenant, tntID.ID, true, utils.NonTransactional) + case utils.StatQueuePrefix: + tntID := utils.NewTenantID(dataID) + _, err = dm.GetStatQueue(tntID.Tenant, tntID.ID, true, utils.NonTransactional) case utils.TimingsPrefix: _, err = dm.GetTiming(dataID, true, utils.NonTransactional) case utils.ThresholdProfilePrefix: diff --git a/engine/onstor_it_test.go b/engine/onstor_it_test.go index 5a7012e26..61cc5ff24 100644 --- a/engine/onstor_it_test.go +++ b/engine/onstor_it_test.go @@ -63,7 +63,12 @@ var sTestsOnStorIT = []func(t *testing.T){ testOnStorITCacheReverseAlias, testOnStorITCacheResource, testOnStorITCacheResourceProfile, + testOnStorITCacheStatQueueProfile, + testOnStorITCacheStatQueue, + testOnStorITCacheThresholdProfile, + testOnStorITCacheThreshold, testOnStorITCacheTiming, + testOnStorITCacheFilter, // ToDo: test cache flush for a prefix // ToDo: testOnStorITLoadAccountingCache testOnStorITHasData, @@ -140,6 +145,7 @@ func testOnStorITFlush(t *testing.T) { } cache.Flush() } + func testOnStorITIsDBEmpty(t *testing.T) { test, err := onStor.DataDB().IsDBEmpty() if err != nil { @@ -147,7 +153,6 @@ func testOnStorITIsDBEmpty(t *testing.T) { } else if test != true { t.Errorf("\nExpecting: true got :%+v", test) } - } func testOnStorITSetGetDerivedCharges(t *testing.T) { @@ -896,7 +901,199 @@ func testOnStorITCacheResource(t *testing.T) { } else if rcv := itm.(*Resource); !reflect.DeepEqual(res, rcv) { t.Errorf("Expecting: %+v, received: %+v", res, rcv) } +} +func testOnStorITCacheStatQueueProfile(t *testing.T) { + statProfile := &StatQueueProfile{ + Tenant: "cgrates.org", + ID: "Test_Stat_Cache", + FilterIDs: []string{"FLTR_1"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + QueueLength: 10, + TTL: time.Duration(10) * time.Second, + Metrics: []string{"ASR"}, + Thresholds: []string{"Th1"}, + Blocker: true, + Stored: true, + Weight: 20, + MinItems: 1, + } + if err := onStor.SetStatQueueProfile(statProfile); err != nil { + t.Error(err) + } + expectedR := []string{"sqp_cgrates.org:Test_Stat_Cache"} + if itm, err := onStor.DataDB().GetKeysForPrefix(utils.StatQueueProfilePrefix); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedR, itm) { + t.Errorf("Expected : %+v, but received %+v", expectedR, itm) + } + if _, hasIt := cache.Get(utils.StatQueueProfilePrefix + statProfile.TenantID()); hasIt { + t.Error("Already in cache") + } + if err := onStor.CacheDataFromDB(utils.StatQueueProfilePrefix, []string{statProfile.TenantID()}, false); err != nil { + t.Error(err) + } + if itm, hasIt := cache.Get(utils.StatQueueProfilePrefix + statProfile.TenantID()); !hasIt { + t.Error("Did not cache") + } else if rcv := itm.(*StatQueueProfile); !reflect.DeepEqual(statProfile, rcv) { + t.Errorf("Expecting: %+v, received: %+v", statProfile, rcv) + } +} + +func testOnStorITCacheStatQueue(t *testing.T) { + eTime := utils.TimePointer(time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC).Local()) + sq := &StatQueue{ + Tenant: "cgrates.org", + ID: "Test_StatQueue_Cache", + SQItems: []struct { + EventID string // Bounded to the original StatEvent + ExpiryTime *time.Time // Used to auto-expire events + }{{EventID: "cgrates.org:ev1", ExpiryTime: eTime}, + {EventID: "cgrates.org:ev2", ExpiryTime: eTime}, + {EventID: "cgrates.org:ev3", ExpiryTime: eTime}}, + SQMetrics: map[string]StatMetric{ + utils.MetaASR: &StatASR{ + Answered: 2, + Count: 3, + Events: map[string]bool{ + "cgrates.org:ev1": true, + "cgrates.org:ev2": true, + "cgrates.org:ev3": false, + }, + }, + }, + } + if err := onStor.SetStatQueue(sq); err != nil { + t.Error(err) + } + expectedT := []string{"stq_cgrates.org:Test_StatQueue_Cache"} + if itm, err := onStor.DataDB().GetKeysForPrefix(utils.StatQueuePrefix); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedT, itm) { + t.Errorf("Expected : %+v, but received %+v", expectedT, itm) + } + + if _, hasIt := cache.Get(utils.StatQueuePrefix + sq.TenantID()); hasIt { + t.Error("Already in cache") + } + if err := onStor.CacheDataFromDB(utils.StatQueuePrefix, []string{sq.TenantID()}, false); err != nil { + t.Error(err) + } + if itm, hasIt := cache.Get(utils.StatQueuePrefix + sq.TenantID()); !hasIt { + t.Error("Did not cache") + } else if rcv := itm.(*StatQueue); !reflect.DeepEqual(sq, rcv) { + t.Errorf("Expecting: %+v, received: %+v", sq, rcv) + } +} + +func testOnStorITCacheThresholdProfile(t *testing.T) { + tPrfl := &ThresholdProfile{ + Tenant: "cgrates.org", + ID: "Test_Threshold_Cache", + FilterIDs: []string{"FilterID1", "FilterID2"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + Recurrent: true, + MinSleep: time.Duration(5 * time.Minute), + Blocker: false, + Weight: 20.0, + ActionIDs: []string{"ACT_1", "ACT_2"}, + Async: true, + } + if err := onStor.SetThresholdProfile(tPrfl); err != nil { + t.Error(err) + } + expectedR := []string{"thp_cgrates.org:Test_Threshold_Cache"} + if itm, err := onStor.DataDB().GetKeysForPrefix(utils.ThresholdProfilePrefix); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedR, itm) { + t.Errorf("Expected : %+v, but received %+v", expectedR, itm) + } + if _, hasIt := cache.Get(utils.ThresholdProfilePrefix + tPrfl.TenantID()); hasIt { + t.Error("Already in cache") + } + if err := onStor.CacheDataFromDB(utils.ThresholdProfilePrefix, []string{tPrfl.TenantID()}, false); err != nil { + t.Error(err) + } + if itm, hasIt := cache.Get(utils.ThresholdProfilePrefix + tPrfl.TenantID()); !hasIt { + t.Error("Did not cache") + } else if rcv := itm.(*ThresholdProfile); !reflect.DeepEqual(tPrfl, rcv) { + t.Errorf("Expecting: %+v, received: %+v", tPrfl, rcv) + } +} + +func testOnStorITCacheThreshold(t *testing.T) { + th := &Threshold{ + Tenant: "cgrates.org", + ID: "Test_Th_Cache", + Hits: 2, + Snooze: time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC).Local(), + } + if err := onStor.SetThreshold(th); err != nil { + t.Error(err) + } + expectedT := []string{"thd_cgrates.org:Test_Th_Cache"} + if itm, err := onStor.DataDB().GetKeysForPrefix(utils.ThresholdPrefix); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedT, itm) { + t.Errorf("Expected : %+v, but received %+v", expectedT, itm) + } + + if _, hasIt := cache.Get(utils.ThresholdPrefix + th.TenantID()); hasIt { + t.Error("Already in cache") + } + if err := onStor.CacheDataFromDB(utils.ThresholdPrefix, []string{th.TenantID()}, false); err != nil { + t.Error(err) + } + if itm, hasIt := cache.Get(utils.ThresholdPrefix + th.TenantID()); !hasIt { + t.Error("Did not cache") + } else if rcv := itm.(*Threshold); !reflect.DeepEqual(th, rcv) { + t.Errorf("Expecting: %+v, received: %+v", th, rcv) + } +} + +func testOnStorITCacheFilter(t *testing.T) { + filter := &Filter{ + Tenant: "cgrates.org", + ID: "Filter1", + RequestFilters: []*RequestFilter{ + &RequestFilter{ + FieldName: "*string", + Type: "Account", + Values: []string{"1001", "1002"}, + }, + }, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + } + if err := onStor.SetFilter(filter); err != nil { + t.Error(err) + } + expectedT := []string{"ftr_cgrates.org:Filter1"} + if itm, err := onStor.DataDB().GetKeysForPrefix(utils.FilterPrefix); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedT, itm) { + t.Errorf("Expected : %+v, but received %+v", expectedT, itm) + } + + if _, hasIt := cache.Get(utils.FilterPrefix + filter.TenantID()); hasIt { + t.Error("Already in cache") + } + if err := onStor.CacheDataFromDB(utils.FilterPrefix, []string{filter.TenantID()}, false); err != nil { + t.Error(err) + } + if itm, hasIt := cache.Get(utils.FilterPrefix + filter.TenantID()); !hasIt { + t.Error("Did not cache") + } else if rcv := itm.(*Filter); !reflect.DeepEqual(filter, rcv) { + t.Errorf("Expecting: %+v, received: %+v", filter, rcv) + } } func testOnStorITHasData(t *testing.T) { diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 1c350ee6e..7e7470b8a 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -1371,8 +1371,7 @@ func (rs *RedisStorage) GetStatQueueProfileDrv(tenant string, id string) (sq *St // SetStatsQueueDrv stores a StatsQueue into DataDB func (rs *RedisStorage) SetStatQueueProfileDrv(sq *StatQueueProfile) (err error) { - var result []byte - result, err = rs.ms.Marshal(sq) + result, err := rs.ms.Marshal(sq) if err != nil { return } diff --git a/general_tests/tut_smgeneric_it_test.go b/general_tests/tut_smgeneric_it_test.go index 4b1f25006..e2aaf044f 100644 --- a/general_tests/tut_smgeneric_it_test.go +++ b/general_tests/tut_smgeneric_it_test.go @@ -100,8 +100,8 @@ func TestTutSMGCacheStats(t *testing.T) { var rcvStats *utils.CacheStats expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, - CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, - StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} var args utils.AttrCacheStats if err := tutSMGRpc.Call("ApierV2.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV2.GetCacheStats: ", err.Error()) diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index d4532c3d3..c31553d2d 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -104,8 +104,8 @@ func TestTutITCacheStats(t *testing.T) { var rcvStats *utils.CacheStats expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, - CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 0, - StatQueueProfiles: 0, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} var args utils.AttrCacheStats if err := tutLocalRpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) From ffc7b3d0eb18530ff9e1553f34204ca7e5146254 Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 12 Nov 2017 17:46:35 +0100 Subject: [PATCH 39/75] Nicer logging for config failing --- cmd/cgr-engine/cgr-engine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 3a3c29254..2ff1bc6d8 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -739,7 +739,7 @@ func main() { // Init config cfg, err = config.NewCGRConfigFromFolder(*cfgDir) if err != nil { - log.Fatalf("Could not parse config: ", err) + log.Fatalf("Could not parse config: <%s>", err.Error()) return } config.SetCgrConfig(cfg) // Share the config object From 83836e27493041f349bf39842b5c8e5c884e8f40 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 13 Nov 2017 16:44:51 +0100 Subject: [PATCH 40/75] Aliases should consider *any as destination ID before going into prefixes --- engine/aliases.go | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/engine/aliases.go b/engine/aliases.go index 9286aefcb..34dd1f574 100644 --- a/engine/aliases.go +++ b/engine/aliases.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "fmt" "reflect" "sort" "strings" @@ -407,30 +408,43 @@ func LoadAlias(attr *AttrMatchingAlias, in interface{}, extraFields string) erro rightPairs = values[0].Pairs } + if rightPairs == nil { // attempt to match on *any destination, so we don't longer look for prefixes + for _, value := range values { + if value.DestinationId == utils.ANY { + rightPairs = value.Pairs + break + } + } + } + if rightPairs == nil { // check destination ids for _, p := range utils.SplitPrefix(attr.Destination, MIN_PREFIX_MATCH) { - if destIDs, err := dm.DataDB().GetReverseDestination(p, false, utils.NonTransactional); err == nil { - for _, value := range values { - for _, dId := range destIDs { - if value.DestinationId == utils.ANY || value.DestinationId == dId { - rightPairs = value.Pairs - } - if rightPairs != nil { - break - } + destIDs, err := dm.DataDB().GetReverseDestination(p, false, utils.NonTransactional) + if err != nil { + if err.Error() != utils.ErrNotFound.Error() { // no reverse found + return err + } + continue + } + for _, value := range values { + for _, dId := range destIDs { + if value.DestinationId == dId { + rightPairs = value.Pairs } if rightPairs != nil { break } } + if rightPairs != nil { + break + } } if rightPairs != nil { break } } } - if rightPairs != nil { // change values in the given object v := reflect.ValueOf(in) From a47eb109b0adb8f28e7f30870756009b0aefa196 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 13 Nov 2017 16:45:15 +0100 Subject: [PATCH 41/75] Unused export --- engine/aliases.go | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/aliases.go b/engine/aliases.go index 34dd1f574..6de6aebd4 100644 --- a/engine/aliases.go +++ b/engine/aliases.go @@ -19,7 +19,6 @@ along with this program. If not, see package engine import ( - "fmt" "reflect" "sort" "strings" From 62d875c221ab07bf753dec458c394e20a16bac97 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 14 Nov 2017 08:33:42 +0100 Subject: [PATCH 42/75] RSR Filters with | as separator --- utils/consts.go | 1 + utils/rsrfield.go | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/utils/consts.go b/utils/consts.go index 22e56ed5b..e864b7aa5 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -147,6 +147,7 @@ const ( CSV_SEP = ',' FALLBACK_SEP = ';' INFIELD_SEP = ";" + SUBFIELD_SEP = "|" FIELDS_SEP = "," InInFieldSep = ":" STATIC_HDRVAL_SEP = "::" diff --git a/utils/rsrfield.go b/utils/rsrfield.go index d26cb67a6..c2b15bdba 100644 --- a/utils/rsrfield.go +++ b/utils/rsrfield.go @@ -24,7 +24,7 @@ import ( "strings" ) -func NewRSRField(fldStr string) (*RSRField, error) { +func NewRSRField(fldStr string) (fld *RSRField, err error) { if len(fldStr) == 0 { return nil, nil } @@ -35,12 +35,10 @@ func NewRSRField(fldStr string) (*RSRField, error) { if fltrStart < 1 { return nil, fmt.Errorf("Invalid FilterStartValue in string: %s", fldStr) } - for _, fltrVal := range strings.Split(fldStr[fltrStart+1:len(fldStr)-1], INFIELD_SEP) { - if rsrFltr, err := NewRSRFilter(fltrVal); err != nil { - return nil, fmt.Errorf("Invalid FilterValue in string: %s, err: %s", fltrVal, err.Error()) - } else { - filters = append(filters, rsrFltr) - } + fltrVal := fldStr[fltrStart+1 : len(fldStr)-1] + filters, err = ParseRSRFilters(fltrVal, SUBFIELD_SEP) + if err != nil { + return nil, fmt.Errorf("Invalid FilterValue in string: %s, err: %s", fltrVal, err.Error()) } fldStr = fldStr[:fltrStart] // Take the filter part out before compiling further @@ -149,12 +147,16 @@ func (rsrf *RSRField) RegexpMatched() bool { // Investigate whether we had a reg } func (rsrf *RSRField) FilterPasses(value string) bool { + fmt.Printf("RSRField: %s, filterPasses value: <%q>\n", ToJSON(rsrf), value) if len(rsrf.filters) == 0 { // No filters return true } parsedVal := rsrf.ParseValue(value) + fmt.Printf("parsedVal: %s\n", parsedVal) filterPasses := false + fmt.Printf("having filters: %s, len(filters): %d\n", ToJSON(rsrf.filters), len(rsrf.filters)) for _, fltr := range rsrf.filters { + fmt.Printf("Checking filter: %s") if fltr.Pass(parsedVal) { filterPasses = true } @@ -192,6 +194,7 @@ type RSRFilter struct { } func (rsrFltr *RSRFilter) Pass(val string) bool { + fmt.Printf("Filter with rule: %s, parsing val: %q\n", rsrFltr.filterRule, val) if rsrFltr.filterRule == "" { return !rsrFltr.negative } From 239b5678dc3d2520a04d5952df911c4bcde9dbb5 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 14 Nov 2017 08:43:11 +0100 Subject: [PATCH 43/75] Using MetaPipe (*|) as in-filter separator --- utils/consts.go | 2 +- utils/rsrfield.go | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/utils/consts.go b/utils/consts.go index e864b7aa5..ac8c9f21c 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -147,7 +147,7 @@ const ( CSV_SEP = ',' FALLBACK_SEP = ';' INFIELD_SEP = ";" - SUBFIELD_SEP = "|" + MetaPipe = "*|" FIELDS_SEP = "," InInFieldSep = ":" STATIC_HDRVAL_SEP = "::" diff --git a/utils/rsrfield.go b/utils/rsrfield.go index c2b15bdba..9ce3bf0dc 100644 --- a/utils/rsrfield.go +++ b/utils/rsrfield.go @@ -36,7 +36,7 @@ func NewRSRField(fldStr string) (fld *RSRField, err error) { return nil, fmt.Errorf("Invalid FilterStartValue in string: %s", fldStr) } fltrVal := fldStr[fltrStart+1 : len(fldStr)-1] - filters, err = ParseRSRFilters(fltrVal, SUBFIELD_SEP) + filters, err = ParseRSRFilters(fltrVal, MetaPipe) if err != nil { return nil, fmt.Errorf("Invalid FilterValue in string: %s, err: %s", fltrVal, err.Error()) } @@ -147,16 +147,12 @@ func (rsrf *RSRField) RegexpMatched() bool { // Investigate whether we had a reg } func (rsrf *RSRField) FilterPasses(value string) bool { - fmt.Printf("RSRField: %s, filterPasses value: <%q>\n", ToJSON(rsrf), value) if len(rsrf.filters) == 0 { // No filters return true } parsedVal := rsrf.ParseValue(value) - fmt.Printf("parsedVal: %s\n", parsedVal) filterPasses := false - fmt.Printf("having filters: %s, len(filters): %d\n", ToJSON(rsrf.filters), len(rsrf.filters)) for _, fltr := range rsrf.filters { - fmt.Printf("Checking filter: %s") if fltr.Pass(parsedVal) { filterPasses = true } @@ -194,7 +190,6 @@ type RSRFilter struct { } func (rsrFltr *RSRFilter) Pass(val string) bool { - fmt.Printf("Filter with rule: %s, parsing val: %q\n", rsrFltr.filterRule, val) if rsrFltr.filterRule == "" { return !rsrFltr.negative } From f43dd4d35d3ed05e9c0729b196312935ee264e3c Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 14 Nov 2017 12:10:13 +0100 Subject: [PATCH 44/75] Support for timestamp with timezone containing offset as ID --- utils/coreutils.go | 3 +++ utils/coreutils_test.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/utils/coreutils.go b/utils/coreutils.go index cfe658a4f..7599de56e 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -165,6 +165,7 @@ func ParseTimeDetectLayout(tmStr string, timezone string) (time.Time, error) { rfc3339Rule := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.+$`) sqlRule := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$`) gotimeRule := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.?\d*\s[+,-]\d+\s\w+$`) + gotimeRule2 := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.?\d*\s[+,-]\d+\s[+,-]\d+$`) fsTimestamp := regexp.MustCompile(`^\d{16}$`) astTimestamp := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d*[+,-]\d+$`) unixTimestampRule := regexp.MustCompile(`^\d{10}$`) @@ -179,6 +180,8 @@ func ParseTimeDetectLayout(tmStr string, timezone string) (time.Time, error) { return time.Parse(time.RFC3339, tmStr) case gotimeRule.MatchString(tmStr): return time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", tmStr) + case gotimeRule2.MatchString(tmStr): + return time.Parse("2006-01-02 15:04:05.999999999 -0700 -0700", tmStr) case sqlRule.MatchString(tmStr): return time.ParseInLocation("2006-01-02 15:04:05", tmStr, loc) case fsTimestamp.MatchString(tmStr): diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index b3e481f1f..962dc3e3b 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -153,6 +153,22 @@ func TestParseTimeDetectLayout(t *testing.T) { if err == nil { t.Errorf("Expecting error") } + loc, err := time.LoadLocation("Asia/Kabul") + if err != nil { + t.Error(err) + } + expectedTime = time.Date(2013, 12, 30, 15, 0, 1, 0, loc) + goTmStr2 := "2013-12-30 15:00:01 +0430 +0430" + goTm, err = ParseTimeDetectLayout(goTmStr2, "") + if err != nil { + t.Error(err) + } else if !goTm.Equal(expectedTime) { + t.Errorf("Unexpected time parsed: %v, expecting: %v", goTm, expectedTime) + } + //goTmStr2 = "2013-12-30 15:00:01 +0430" + //if _, err = ParseTimeDetectLayout(goTmStr2, ""); err != nil { + // t.Errorf("Expecting error") + //} fsTmstampStr := "1394291049287234" fsTm, err := ParseTimeDetectLayout(fsTmstampStr, "") expectedTime = time.Date(2014, 3, 8, 15, 4, 9, 287234000, time.UTC) From c35b2a90bbe166ef4e070365249636713899f20c Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Tue, 14 Nov 2017 13:16:02 +0000 Subject: [PATCH 45/75] Added move feature(to migrate data from one db to another) and updated GetTPIds , IsDBempty and the versioning accordingly --- apier/v1/tp.go | 2 +- cmd/cgr-migrator/cgr-migrator.go | 83 +-- data/storage/migrator/usage_float_to_int.sql | 2 +- engine/loader_it_test.go | 2 +- engine/storage_csv.go | 2 +- engine/storage_interface.go | 2 +- engine/storage_mongo_stordb.go | 40 +- engine/storage_sql.go | 99 +++- engine/version.go | 53 +- engine/versions_it_test.go | 34 +- migrator/accounts.go | 62 ++- migrator/action.go | 67 ++- migrator/action_plan.go | 63 ++- migrator/action_trigger.go | 69 ++- migrator/alias.go | 134 +++++ migrator/cdrstats.go | 71 +++ migrator/derived_chargers.go | 78 +++ migrator/destinations.go | 132 +++++ migrator/lcr.go | 78 +++ migrator/migrator.go | 236 ++++++++- migrator/{v1datadb.go => migratorDataDB.go} | 2 +- migrator/migrator_it_test.go | 528 ++++++++++++++++--- migrator/rating_plan.go | 78 +++ migrator/rating_profile.go | 78 +++ migrator/request_filter.go | 78 +++ migrator/resource.go | 80 +++ migrator/sharedgroup.go | 63 ++- migrator/stats.go | 108 +++- migrator/subscribers.go | 71 +++ migrator/thresholds.go | 134 +++-- migrator/timings.go | 78 +++ migrator/tp_account_actions.go | 76 +++ migrator/tp_action_plans.go | 83 +++ migrator/tp_action_triggers.go | 83 +++ migrator/tp_actions.go | 83 +++ migrator/tp_aliases.go | 77 +++ migrator/tp_cdr_stats.go | 83 +++ migrator/tp_derived_chargers.go | 78 +++ migrator/tp_destination_rates.go | 82 +++ migrator/tp_destinations.go | 82 +++ migrator/tp_filters.go | 82 +++ migrator/tp_lcrs.go | 76 +++ migrator/tp_rates.go | 83 +++ migrator/tp_rating_plans.go | 83 +++ migrator/tp_rating_profiles.go | 77 +++ migrator/tp_resources.go | 83 +++ migrator/tp_shared_groups.go | 83 +++ migrator/tp_stats.go | 83 +++ migrator/tp_thresholds.go | 83 +++ migrator/tp_timings.go | 83 +++ migrator/tp_users.go | 77 +++ migrator/user.go | 78 +++ migrator/v1migrator_utils.go | 15 +- migrator/v1mongo_data.go | 2 +- migrator/v1redis.go | 30 +- utils/consts.go | 130 ++++- 56 files changed, 4180 insertions(+), 302 deletions(-) create mode 100644 migrator/alias.go create mode 100644 migrator/cdrstats.go create mode 100644 migrator/derived_chargers.go create mode 100644 migrator/destinations.go create mode 100644 migrator/lcr.go rename migrator/{v1datadb.go => migratorDataDB.go} (97%) create mode 100644 migrator/rating_plan.go create mode 100644 migrator/rating_profile.go create mode 100644 migrator/request_filter.go create mode 100644 migrator/resource.go create mode 100644 migrator/subscribers.go create mode 100644 migrator/timings.go create mode 100644 migrator/tp_account_actions.go create mode 100644 migrator/tp_action_plans.go create mode 100644 migrator/tp_action_triggers.go create mode 100644 migrator/tp_actions.go create mode 100644 migrator/tp_aliases.go create mode 100644 migrator/tp_cdr_stats.go create mode 100644 migrator/tp_derived_chargers.go create mode 100644 migrator/tp_destination_rates.go create mode 100644 migrator/tp_destinations.go create mode 100644 migrator/tp_filters.go create mode 100644 migrator/tp_lcrs.go create mode 100644 migrator/tp_rates.go create mode 100644 migrator/tp_rating_plans.go create mode 100644 migrator/tp_rating_profiles.go create mode 100644 migrator/tp_resources.go create mode 100644 migrator/tp_shared_groups.go create mode 100644 migrator/tp_stats.go create mode 100644 migrator/tp_thresholds.go create mode 100644 migrator/tp_timings.go create mode 100644 migrator/tp_users.go create mode 100644 migrator/user.go diff --git a/apier/v1/tp.go b/apier/v1/tp.go index 42291c5ff..9c9b856a0 100644 --- a/apier/v1/tp.go +++ b/apier/v1/tp.go @@ -35,7 +35,7 @@ type AttrGetTPIds struct { // Queries tarrif plan identities gathered from all tables. func (self *ApierV1) GetTPIds(attrs AttrGetTPIds, reply *[]string) error { - if ids, err := self.StorDb.GetTpIds(); err != nil { + if ids, err := self.StorDb.GetTpIds(""); err != nil { return utils.NewErrServerError(err) } else if ids == nil { return utils.ErrNotFound diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index ba7b1ef45..2b7b8d205 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -31,36 +31,37 @@ import ( ) var ( - oldDataDB migrator.V1DataDB + sameDBname true + inDataDB migrator.MigratorDataDB oldstorDB engine.Storage oStorDBType string - odataDBType string + oDataDBType string oDBDataEncoding string migrate = flag.String("migrate", "", "Fire up automatic migration *to use multiple values use ',' as separator \n <*set_versions|*cost_details|*accounts|*actions|*action_triggers|*action_plans|*shared_groups> ") version = flag.Bool("version", false, "Prints the application version.") - dataDBType = flag.String("datadb_type", config.CgrConfig().DataDbType, "The type of the DataDb database ") - dataDBHost = flag.String("datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") - dataDBPort = flag.String("datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") - dataDBName = flag.String("datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") - dataDBUser = flag.String("datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") - dataDBPass = flag.String("datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") + outDataDBType = flag.String("out_datadb_type", config.CgrConfig().DataDbType, "The type of the DataDb Database ") + outDataDBHost = flag.String("out_datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") + outDataDBPort = flag.String("out_datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") + outDataDBName = flag.String("out_datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") + outDataDBUser = flag.String("out_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") + outDataDBPass = flag.String("out_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") - storDBType = flag.String("stordb_type", config.CgrConfig().StorDBType, "The type of the storDb database ") + storDBType = flag.String("stordb_type", config.CgrConfig().StorDBType, "The type of the storDb Database ") storDBHost = flag.String("stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") storDBPort = flag.String("stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") storDBName = flag.String("stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") storDBUser = flag.String("stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") storDBPass = flag.String("stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") - oldDataDBType = flag.String("old_datadb_type", "", "The type of the DataDb database ") - oldDataDBHost = flag.String("old_datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") - oldDataDBPort = flag.String("old_datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") - oldDataDBName = flag.String("old_datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") - oldDataDBUser = flag.String("old_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") - oldDataDBPass = flag.String("old_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") + inDataDBType = flag.String("in_datadb_type", "", "The type of the DataDb Database ") + inDataDBHost = flag.String("in_datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") + inDataDBPort = flag.String("in_datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") + inDataDBName = flag.String("in_datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") + inDataDBUser = flag.String("in_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") + inDataDBPass = flag.String("in_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") - oldStorDBType = flag.String("old_stordb_type", "", "The type of the storDb database ") + oldStorDBType = flag.String("old_stordb_type", "", "The type of the storDb Database ") oldStorDBHost = flag.String("old_stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") oldStorDBPort = flag.String("old_stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") oldStorDBName = flag.String("old_stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") @@ -70,11 +71,11 @@ var ( loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") oldLoadHistorySize = flag.Int("old_load_history_size", 0, "Limit the number of records in the load history") - dbDataEncoding = flag.String("dbdata_encoding", config.CgrConfig().DBDataEncoding, "The encoding used to store object data in strings") - oldDBDataEncoding = flag.String("old_dbdata_encoding", "", "The encoding used to store object data in strings") - dryRun = flag.Bool("dry_run", false, "When true will not save loaded data to dataDb but just parse it for consistency and errors.") - verbose = flag.Bool("verbose", false, "Enable detailed verbose logging output") - stats = flag.Bool("stats", false, "Generates statsistics about migrated data.") + dbDataEncoding = flag.String("dbData_encoding", config.CgrConfig().DBDataEncoding, "The encoding used to store object Data in strings") + inDBDataEncoding = flag.String("in_dbData_encoding", "", "The encoding used to store object Data in strings") + dryRun = flag.Bool("dry_run", false, "When true will not save loaded Data to DataDb but just parse it for consistency and errors.") + verbose = flag.Bool("verbose", false, "Enable detailed verbose logging output") + stats = flag.Bool("stats", false, "Generates statsistics about migrated Data.") ) func main() { @@ -85,31 +86,30 @@ func main() { } if migrate != nil && *migrate != "" { // Run migrator if *verbose { - log.Print("Initializing dataDB:", *dataDBType) + log.Print("Initializing DataDB:", *outDataDBType) log.Print("Initializing storDB:", *storDBType) } - var dm *engine.DataManager - dm, _ = engine.ConfigureDataStorage(*dataDBType, *dataDBHost, *dataDBPort, *dataDBName, - *dataDBUser, *dataDBPass, *dbDataEncoding, config.CgrConfig().CacheCfg(), *loadHistorySize) - storDB, err := engine.ConfigureStorStorage(*storDBType, *storDBHost, *storDBPort, - *storDBName, *storDBUser, *storDBPass, *dbDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, - config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + var dmOUT *engine.DataManager + dmOUT, _ = engine.ConfigureDataStorage(*outDataDBType, *outDataDBHost, *outDataDBPort, *outDataDBName, *outDataDBUser, *outDataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) + storDB, err := engine.ConfigureStorStorage(*storDBType, *storDBHost, *storDBPort, *storDBName, *storDBUser, *storDBPass, *dbDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } - if *oldDataDBType == "" { - *oldDataDBType = *dataDBType - *oldDataDBHost = *dataDBHost - *oldDataDBPort = *dataDBPort - *oldDataDBName = *dataDBName - *oldDataDBUser = *dataDBUser - *oldDataDBPass = *dataDBPass + if *inDataDBType == "" { + *inDataDBType = *outDataDBType + *inDataDBHost = *outDataDBHost + *inDataDBPort = *outDataDBPort + *inDataDBName = *outDataDBName + *inDataDBUser = *outDataDBUser + *inDataDBPass = *outDataDBPass } if *verbose { - log.Print("Initializing oldDataDB:", *oldDataDBType) + log.Print("Initializing inDataDB:", *inDataDBType) } - oldDataDB, err := migrator.ConfigureV1DataStorage(*oldDataDBType, *oldDataDBHost, *dataDBPort, *dataDBName, *dataDBUser, *dataDBPass, *dbDataEncoding) + var dmIN *engine.DataManager + dmIN, _ = engine.ConfigureDataStorage(*inDataDBType, *inDataDBHost, *inDataDBPort, *inDataDBName, *inDataDBUser, *inDataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) + inDataDB, err := migrator.ConfigureV1DataStorage(*inDataDBType, *inDataDBHost, *inDataDBPort, *inDataDBName, *inDataDBUser, *inDataDBPass, *dbDataEncoding) if err != nil { log.Fatal(err) } @@ -123,7 +123,7 @@ func main() { } } if *oldStorDBType != "" { - oldstorDB, err = engine.ConfigureStorStorage(oStorDBType, *oldStorDBHost, *oldStorDBPort, *oldStorDBName, *oldStorDBUser, *oldStorDBPass, *oldDBDataEncoding, + oldstorDB, err = engine.ConfigureStorStorage(oStorDBType, *oldStorDBHost, *oldStorDBPort, *oldStorDBName, *oldStorDBUser, *oldStorDBPass, *inDBDataEncoding, config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) @@ -132,7 +132,10 @@ func main() { if *verbose { log.Print("Migrating: ", *migrate) } - m, err := migrator.NewMigrator(dm, *dataDBType, *dbDataEncoding, storDB, *storDBType, oldDataDB, *oldDataDBType, *oldDBDataEncoding, oldstorDB, *oldStorDBType, *dryRun) + if inDataDBName != outDataDBName { + sameDBname := false + } + m, err := migrator.NewMigrator(dmIN, dmOUT, *outDataDBType, *dbDataEncoding, storDB, *storDBType, inDataDB, *inDataDBType, *inDBDataEncoding, oldstorDB, *oldStorDBType, *dryRun, sameDBname) if err != nil { log.Fatal(err) } diff --git a/data/storage/migrator/usage_float_to_int.sql b/data/storage/migrator/usage_float_to_int.sql index 9061b2ceb..1e4df20cc 100644 --- a/data/storage/migrator/usage_float_to_int.sql +++ b/data/storage/migrator/usage_float_to_int.sql @@ -1,4 +1,4 @@ -ALTER TABLE cdrs CHANGE COLUMN `usage` `usage_old` DECIMAL(30,9); +ALTER TABLE cdrs CHANGE COLUMN `usage` `usage_old` DECIMAL(30); ALTER TABLE cdrs ADD `usage` BIGINT; UPDATE cdrs SET `usage` = `usage_old` * 1000000000 WHERE usage_old IS NOT NULL; ALTER TABLE cdrs DROP COLUMN usage_old; \ No newline at end of file diff --git a/engine/loader_it_test.go b/engine/loader_it_test.go index 2ca9e484f..ad6c89f55 100755 --- a/engine/loader_it_test.go +++ b/engine/loader_it_test.go @@ -367,7 +367,7 @@ func TestLoaderITImportToStorDb(t *testing.T) { if err := csvImporter.Run(); err != nil { t.Error("Error when importing tpdata to storDb: ", err) } - if tpids, err := storDb.GetTpIds(); err != nil { + if tpids, err := storDb.GetTpIds(""); err != nil { t.Error("Error when querying storDb for imported data: ", err) } else if len(tpids) != 1 || tpids[0] != utils.TEST_SQL { t.Errorf("Data in storDb is different than expected %v", tpids) diff --git a/engine/storage_csv.go b/engine/storage_csv.go index f7b55867e..8359a36b5 100755 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -705,7 +705,7 @@ func (csvs *CSVStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return tpFilter.AsTPFilter(), nil } -func (csvs *CSVStorage) GetTpIds() ([]string, error) { +func (csvs *CSVStorage) GetTpIds(x string) ([]string, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 40c389626..d8b2e6297 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -153,7 +153,7 @@ type LoadStorage interface { // LoadReader reads from .csv or TP tables and provides the data ready for the tp_db or data_db. type LoadReader interface { - GetTpIds() ([]string, error) + GetTpIds(string) ([]string, error) GetTpTableIds(string, string, utils.TPDistinctIds, map[string]string, *utils.Paginator) ([]string, error) GetTPTimings(string, string) ([]*utils.ApierTPTiming, error) GetTPDestinations(string, string) ([]*utils.TPDestination, error) diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index f21ede633..796e68e78 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -28,31 +28,47 @@ import ( "time" ) -func (ms *MongoStorage) GetTpIds() ([]string, error) { +func (ms *MongoStorage) GetTpIds(x string) ([]string, error) { tpidMap := make(map[string]bool) session := ms.session.Copy() db := session.DB(ms.db) defer session.Close() - cols, err := db.CollectionNames() - if err != nil { - return nil, err - } - for _, col := range cols { - if strings.HasPrefix(col, "tp_") { + var tpids []string + if x != "" { + if strings.HasPrefix(x, "tp_") { tpids := make([]string, 0) - if err := db.C(col).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { + if err := db.C(x).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { return nil, err } for _, tpid := range tpids { tpidMap[tpid] = true } } - } - var tpids []string - for tpid := range tpidMap { - tpids = append(tpids, tpid) + for tpid := range tpidMap { + tpids = append(tpids, tpid) + } + } else { + cols, err := db.CollectionNames() + if err != nil { + return nil, err + } + for _, col := range cols { + if strings.HasPrefix(col, "tp_") { + tpids := make([]string, 0) + if err := db.C(col).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { + return nil, err + } + for _, tpid := range tpids { + tpidMap[tpid] = true + } + } + } + for tpid := range tpidMap { + tpids = append(tpids, tpid) + } } return tpids, nil + } func (ms *MongoStorage) GetTpTableIds(tpid, table string, distinct utils.TPDistinctIds, filter map[string]string, pag *utils.Paginator) ([]string, error) { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index a5280a259..351400690 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -101,11 +101,14 @@ func (self *SQLStorage) CreateTablesFromScript(scriptPath string) error { } func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { - tbls := []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, + tbls := []string{ + utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans, utils.TBLTPRateProfiles, utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, - utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, - utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResources, utils.TBLTPStats} + utils.TBLTPActionTriggers, utils.TBLTPAccountActions, utils.TBLTPDerivedChargers, utils.TBLTPUsers, + utils.TBLTPAliases, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPThresholds, + utils.TBLTPFilters, utils.TBLSMCosts, utils.TBLCDRs, utils.TBLTPActionPlans, utils.TBLVersions, + } for _, tbl := range tbls { if self.db.HasTable(tbl) { return false, nil @@ -115,35 +118,76 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { return true, nil } +// update // Return a list with all TPids defined in the system, even if incomplete, isolated in some table. -func (self *SQLStorage) GetTpIds() ([]string, error) { - rows, err := self.Db.Query( - fmt.Sprintf("(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", - utils.TBLTPTimings, - utils.TBLTPDestinations, - utils.TBLTPRates, - utils.TBLTPDestinationRates, - utils.TBLTPRatingPlans, - utils.TBLTPRateProfiles)) - if err != nil { - return nil, err - } - defer rows.Close() - ids := make([]string, 0) - i := 0 - for rows.Next() { - i++ //Keep here a reference so we know we got at least one - var id string - err = rows.Scan(&id) +func (self *SQLStorage) GetTpIds(x string) ([]string, error) { + if x != "" { + rows, err := self.Db.Query( + fmt.Sprintf(" (SELECT tpid FROM %s)", x)) if err != nil { return nil, err } - ids = append(ids, id) + defer rows.Close() + ids := make([]string, 0) + i := 0 + for rows.Next() { + i++ //Keep here a reference so we know we got at least one + var id string + err = rows.Scan(&id) + if err != nil { + return nil, err + } + ids = append(ids, id) + } + if i == 0 { + return nil, nil + } + return ids, nil + } else { + rows, err := self.Db.Query( + fmt.Sprintf( + "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", + utils.TBLTPTimings, + utils.TBLTPDestinations, + utils.TBLTPRates, + utils.TBLTPDestinationRates, + utils.TBLTPRatingPlans, + utils.TBLTPRateProfiles, + utils.TBLTPSharedGroups, + utils.TBLTPCdrStats, + utils.TBLTPLcrs, + utils.TBLTPActions, + utils.TBLTPActionTriggers, + utils.TBLTPAccountActions, + utils.TBLTPDerivedChargers, + utils.TBLTPUsers, + utils.TBLTPAliases, + utils.TBLTPResources, + utils.TBLTPStats, + utils.TBLTPThresholds, + utils.TBLTPFilters, + utils.TBLTPActionPlans)) + if err != nil { + return nil, err + } + defer rows.Close() + ids := make([]string, 0) + i := 0 + for rows.Next() { + i++ //Keep here a reference so we know we got at least one + var id string + err = rows.Scan(&id) + if err != nil { + return nil, err + } + ids = append(ids, id) + } + if i == 0 { + return nil, nil + } + + return ids, nil } - if i == 0 { - return nil, nil - } - return ids, nil } // ToDo: TEST @@ -206,6 +250,7 @@ func (self *SQLStorage) GetTpTableIds(tpid, table string, distinct utils.TPDisti func (self *SQLStorage) RemTpData(table, tpid string, args map[string]string) error { tx := self.db.Begin() + if len(table) == 0 { // Remove tpid out of all tables for _, tblName := range []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans, utils.TBLTPRateProfiles, utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, diff --git a/engine/version.go b/engine/version.go index ec7d7ffb8..b17a29228 100644 --- a/engine/version.go +++ b/engine/version.go @@ -128,11 +128,60 @@ func CurrentDBVersions(storType string) Versions { } func CurrentDataDBVersions() Versions { - return Versions{utils.StatS: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.Thresholds: 2} + return Versions{ + utils.StatS: 2, + utils.Accounts: 2, + utils.Actions: 2, + utils.ActionTriggers: 2, + utils.ActionPlans: 2, + utils.SharedGroups: 2, + utils.Thresholds: 2, + utils.Timing: 2, + utils.RQF: 2, + utils.Resource: 2, + utils.ReverseAlias: 2, + utils.Alias: 2, + utils.User: 2, + utils.Subscribers: 2, + utils.DerivedChargersV: 2, + utils.CdrStats: 2, + utils.Destinations: 2, + utils.ReverseDestinations: 2, + utils.LCR: 2, + utils.RatingPlan: 2, + utils.RatingProfile: 2, + } } func CurrentStorDBVersions() Versions { - return Versions{utils.COST_DETAILS: 2} + return Versions{ + utils.COST_DETAILS: 2, + utils.TpRatingPlans: 2, + utils.TpLcrs: 2, + utils.TpFilters: 2, + utils.TpDestinationRates: 2, + utils.TpActionTriggers: 2, + utils.TpAccountActions: 2, + utils.TpActionPlans: 2, + utils.TpActions: 2, + utils.TpDerivedCharges: 2, + utils.TpThresholds: 2, + utils.TpStats: 2, + utils.TpSharedGroups: 2, + utils.TpRatingProfiles: 2, + utils.TpResources: 2, + utils.TpRates: 2, + utils.TpTiming: 2, + utils.TpResource: 2, + utils.TpAliases: 2, + utils.TpUsers: 2, + utils.TpDerivedChargersV: 2, + utils.TpCdrStats: 2, + utils.TpDestinations: 2, + utils.TpLCR: 2, + utils.TpRatingPlan: 2, + utils.TpRatingProfile: 2, + } } // Versions will keep trac of various item versions diff --git a/engine/versions_it_test.go b/engine/versions_it_test.go index 9b38aff9f..6dd14e163 100644 --- a/engine/versions_it_test.go +++ b/engine/versions_it_test.go @@ -126,16 +126,29 @@ func testVersion(t *testing.T) { var test string var currentVersion Versions var testVersion Versions + dataDbVersions := CurrentDataDBVersions() + storDbVersions := CurrentStorDBVersions() + + allVersions := make(Versions) + for k, v := range dataDbVersions { + allVersions[k] = v + } + for k, v := range storDbVersions { + allVersions[k] = v + } + storType := dm3.DataDB().GetStorageType() switch storType { case utils.MONGO, utils.MAPSTOR: - currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, - utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} - testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2} + currentVersion = allVersions + testVersion = allVersions + testVersion[utils.Accounts] = 1 test = "Migration needed: please backup cgr data and run : " case utils.REDIS: - currentVersion = CurrentDataDBVersions() - testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + currentVersion = dataDbVersions + testVersion = dataDbVersions + testVersion[utils.Accounts] = 1 + test = "Migration needed: please backup cgr data and run : " } @@ -169,14 +182,21 @@ func testVersion(t *testing.T) { storType = storageDb.GetStorageType() switch storType { case utils.MONGO, utils.MAPSTOR: +<<<<<<< HEAD currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} +======= + currentVersion = allVersions + testVersion = allVersions + testVersion[utils.Accounts] = 1 +>>>>>>> Added move feature(to migrate data from one db to another) and updated GetTPIds , IsDBempty and the versioning accordingly test = "Migration needed: please backup cgr data and run : " case utils.POSTGRES, utils.MYSQL: - currentVersion = CurrentStorDBVersions() - testVersion = Versions{utils.COST_DETAILS: 1} + currentVersion = storDbVersions + testVersion = allVersions + testVersion[utils.COST_DETAILS] = 1 test = "Migration needed: please backup cgr data and run : " } //storageDb diff --git a/migrator/accounts.go b/migrator/accounts.go index 5b19419f5..591bb04c7 100755 --- a/migrator/accounts.go +++ b/migrator/accounts.go @@ -33,7 +33,30 @@ const ( v1AccountTBL = "userbalances" ) -func (m *Migrator) migrateAccounts() (err error) { +func (m *Migrator) migrateCurrentAccounts() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ACCOUNT_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ACCOUNT_PREFIX) + acc, err := m.dmIN.DataDB().GetAccount(idg) + if err != nil { + return err + } + if acc != nil { + if m.dryRun != true { + if err := m.dmOut.DataDB().SetAccount(acc); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV1Accounts() (err error) { var v1Acnt *v1Account for { v1Acnt, err = m.oldDataDB.getv1Account() @@ -46,7 +69,7 @@ func (m *Migrator) migrateAccounts() (err error) { if v1Acnt != nil { acnt := v1Acnt.AsAccount() if m.dryRun != true { - if err = m.dm.DataDB().SetAccount(acnt); err != nil { + if err = m.dmOut.DataDB().SetAccount(acnt); err != nil { return err } m.stats[utils.Accounts] += 1 @@ -57,7 +80,7 @@ func (m *Migrator) migrateAccounts() (err error) { if m.dryRun != true { // All done, update version wtih current one vrs := engine.Versions{utils.Accounts: engine.CurrentStorDBVersions()[utils.Accounts]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -67,6 +90,39 @@ func (m *Migrator) migrateAccounts() (err error) { return } +func (m *Migrator) migrateAccounts() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Accounts] { + case current[utils.Accounts]: + if m.sameDBname { + return + } + if err := m.migrateCurrentAccounts(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1Accounts(); err != nil { + return err + } + } + return +} + type v1Account struct { Id string BalanceMap map[string]v1BalanceChain diff --git a/migrator/action.go b/migrator/action.go index 6fce8b768..0c809ba36 100644 --- a/migrator/action.go +++ b/migrator/action.go @@ -20,6 +20,7 @@ package migrator import ( "fmt" + "strings" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -38,7 +39,30 @@ type v1Action struct { type v1Actions []*v1Action -func (m *Migrator) migrateActions() (err error) { +func (m *Migrator) migrateCurrentActions() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ACTION_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ACTION_PREFIX) + acts, err := m.dmIN.GetActions(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if acts != nil { + if m.dryRun != true { + if err := m.dmOut.SetActions(idg, acts, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV1Actions() (err error) { var v1ACs *v1Actions var acts engine.Actions for { @@ -55,18 +79,18 @@ func (m *Migrator) migrateActions() (err error) { acts = append(acts, act) } - if m.dryRun != true { - if err := m.dm.SetActions(acts[0].Id, acts, utils.NonTransactional); err != nil { + if !m.dryRun { + if err := m.dmOut.SetActions(acts[0].Id, acts, utils.NonTransactional); err != nil { return err } m.stats[utils.Actions] += 1 } } } - if m.dryRun != true { + if !m.dryRun { // All done, update version wtih current one vrs := engine.Versions{utils.Actions: engine.CurrentStorDBVersions()[utils.Actions]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -76,6 +100,39 @@ func (m *Migrator) migrateActions() (err error) { return } +func (m *Migrator) migrateActions() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Actions] { + case current[utils.Actions]: + if m.sameDBname { + return + } + if err := m.migrateCurrentActions(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1Actions(); err != nil { + return err + } + } + return +} + func (v1Act v1Action) AsAction() (act *engine.Action) { act = &engine.Action{ Id: v1Act.Id, diff --git a/migrator/action_plan.go b/migrator/action_plan.go index 61461af43..7bd06a7aa 100644 --- a/migrator/action_plan.go +++ b/migrator/action_plan.go @@ -47,7 +47,31 @@ func (at *v1ActionPlan) IsASAP() bool { return at.Timing.Timing.StartTime == utils.ASAP } -func (m *Migrator) migrateActionPlans() (err error) { +func (m *Migrator) migrateCurrentActionPlans() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ACTION_PLAN_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ACTION_PLAN_PREFIX) + acts, err := m.dmIN.DataDB().GetActionPlan(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if acts != nil { + if m.dryRun != true { + + if err := m.dmOut.DataDB().SetActionPlan(idg, acts, true, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV1ActionPlans() (err error) { var v1APs *v1ActionPlans for { v1APs, err = m.oldDataDB.getV1ActionPlans() @@ -61,7 +85,7 @@ func (m *Migrator) migrateActionPlans() (err error) { for _, v1ap := range *v1APs { ap := v1ap.AsActionPlan() if m.dryRun != true { - if err = m.dm.DataDB().SetActionPlan(ap.Id, ap, true, utils.NonTransactional); err != nil { + if err = m.dmOut.DataDB().SetActionPlan(ap.Id, ap, true, utils.NonTransactional); err != nil { return err } m.stats[utils.ActionPlans] += 1 @@ -72,7 +96,7 @@ func (m *Migrator) migrateActionPlans() (err error) { if m.dryRun != true { // All done, update version wtih current one vrs := engine.Versions{utils.ActionPlans: engine.CurrentDataDBVersions()[utils.ActionPlans]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -82,6 +106,39 @@ func (m *Migrator) migrateActionPlans() (err error) { return } +func (m *Migrator) migrateActionPlans() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.ActionPlans] { + case current[utils.ActionPlans]: + if m.sameDBname { + return + } + if err := m.migrateCurrentActionPlans(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1ActionPlans(); err != nil { + return err + } + } + return +} + func (v1AP v1ActionPlan) AsActionPlan() (ap *engine.ActionPlan) { for idx, actionId := range v1AP.AccountIds { idElements := strings.Split(actionId, "_") diff --git a/migrator/action_trigger.go b/migrator/action_trigger.go index 852cc0b71..c98c1247b 100644 --- a/migrator/action_trigger.go +++ b/migrator/action_trigger.go @@ -52,7 +52,30 @@ type v1ActionTrigger struct { type v1ActionTriggers []*v1ActionTrigger -func (m *Migrator) migrateActionTriggers() (err error) { +func (m *Migrator) migrateCurrentActionTrigger() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ACTION_TRIGGER_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ACTION_TRIGGER_PREFIX) + acts, err := m.dmIN.GetActionTriggers(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if acts != nil { + if m.dryRun != true { + if err := m.dmOut.SetActionTriggers(idg, acts, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV1ActionTrigger() (err error) { var v1ACTs *v1ActionTriggers var acts engine.ActionTriggers for { @@ -69,18 +92,18 @@ func (m *Migrator) migrateActionTriggers() (err error) { acts = append(acts, act) } - if m.dryRun != true { - if err := m.dm.SetActionTriggers(acts[0].ID, acts, utils.NonTransactional); err != nil { + if !m.dryRun { + if err := m.dmOut.SetActionTriggers(acts[0].ID, acts, utils.NonTransactional); err != nil { return err } m.stats[utils.ActionTriggers] += 1 } } } - if m.dryRun != true { + if !m.dryRun { // All done, update version wtih current one vrs := engine.Versions{utils.ActionTriggers: engine.CurrentDataDBVersions()[utils.ActionTriggers]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -90,10 +113,42 @@ func (m *Migrator) migrateActionTriggers() (err error) { return } +func (m *Migrator) migrateActionTriggers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.ActionTriggers] { + case current[utils.ActionTriggers]: + if m.sameDBname { + return + } + if err := m.migrateCurrentActionTrigger(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1ActionTrigger(); err != nil { + return err + } + } + return +} + func (v1Act v1ActionTrigger) AsActionTrigger() (at *engine.ActionTrigger) { at = &engine.ActionTrigger{ - ID: v1Act.Id, - // UniqueID: utils.GenUUID(), + ID: v1Act.Id, ThresholdType: v1Act.ThresholdType, ThresholdValue: v1Act.ThresholdValue, Recurrent: v1Act.Recurrent, diff --git a/migrator/alias.go b/migrator/alias.go new file mode 100644 index 000000000..5ce192c1f --- /dev/null +++ b/migrator/alias.go @@ -0,0 +1,134 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentAlias() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ALIASES_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ALIASES_PREFIX) + usr, err := m.dmIN.DataDB().GetAlias(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if usr != nil { + if m.dryRun != true { + if err := m.dmOut.DataDB().SetAlias(usr, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateCurrentReverseAlias() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.REVERSE_ALIASES_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.REVERSE_ALIASES_PREFIX) + + usrs, err := m.dmIN.DataDB().GetReverseAlias(idg, true, utils.NonTransactional) + if err != nil { + return err + } + for _, usr := range usrs { + alias, err := m.dmIN.DataDB().GetAlias(usr, true, utils.NonTransactional) + if err != nil { + return err + } + if alias != nil { + if err := m.dmOut.DataDB().SetReverseAlias(alias, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateAlias() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Alias] { + case current[utils.Alias]: + if m.sameDBname { + return + } + if err := m.migrateCurrentAlias(); err != nil { + return err + } + return + } + return +} + +func (m *Migrator) migrateReverseAlias() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.ReverseAlias] { + case current[utils.ReverseAlias]: + if m.sameDBname { + return + } + if err := m.migrateCurrentReverseAlias(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/cdrstats.go b/migrator/cdrstats.go new file mode 100644 index 000000000..54469b625 --- /dev/null +++ b/migrator/cdrstats.go @@ -0,0 +1,71 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentCdrStats() (err error) { + cdrsts, err := m.dmIN.GetAllCdrStats() + if err != nil { + return err + } + for _, cdrst := range cdrsts { + if cdrst != nil { + if m.dryRun != true { + if err := m.dmOut.SetCdrStats(cdrst); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateCdrStats() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.CdrStats] { + case current[utils.CdrStats]: + if m.sameDBname { + return + } + if err := m.migrateCurrentCdrStats(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/derived_chargers.go b/migrator/derived_chargers.go new file mode 100644 index 000000000..4309a27b9 --- /dev/null +++ b/migrator/derived_chargers.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentDerivedChargers() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.DERIVEDCHARGERS_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.DERIVEDCHARGERS_PREFIX) + drc, err := m.dmIN.GetDerivedChargers(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if drc != nil { + if m.dryRun != true { + if err := m.dmOut.DataDB().SetDerivedChargers(id, drc, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateDerivedChargers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.DerivedChargersV] { + case current[utils.DerivedChargersV]: + if m.sameDBname { + return + } + if err := m.migrateCurrentDerivedChargers(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/destinations.go b/migrator/destinations.go new file mode 100644 index 000000000..afb94fba0 --- /dev/null +++ b/migrator/destinations.go @@ -0,0 +1,132 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentDestinations() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.DESTINATION_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.DESTINATION_PREFIX) + dst, err := m.dmIN.DataDB().GetDestination(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if dst != nil { + if m.dryRun != true { + if err := m.dmOut.DataDB().SetDestination(dst, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateDestinations() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Destinations] { + case current[utils.Destinations]: + if m.sameDBname { + return + } + if err := m.migrateCurrentDestinations(); err != nil { + return err + } + return + } + return +} + +func (m *Migrator) migrateCurrentReverseDestinations() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.REVERSE_DESTINATION_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + rdst, err := m.dmIN.DataDB().GetReverseDestination(id, true, utils.NonTransactional) + if err != nil { + return err + } + for _, id := range rdst { + rdst, err := m.dmIN.DataDB().GetDestination(id, true, utils.NonTransactional) + if err != nil { + return err + } + if rdst != nil { + if err := m.dmOut.DataDB().SetReverseDestination(rdst, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateReverseDestinations() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.ReverseDestinations] { + case current[utils.ReverseDestinations]: + if m.sameDBname { + return + } + if err := m.migrateCurrentReverseDestinations(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/lcr.go b/migrator/lcr.go new file mode 100644 index 000000000..450c31c91 --- /dev/null +++ b/migrator/lcr.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentLCR() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.LCR_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.LCR_PREFIX) + lcr, err := m.dmIN.GetLCR(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if lcr != nil { + if m.dryRun != true { + if err := m.dmOut.SetLCR(lcr, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateLCR() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.LCR] { + case current[utils.LCR]: + if m.sameDBname { + return + } + if err := m.migrateCurrentLCR(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/migrator.go b/migrator/migrator.go index 4f1647e71..81c86f155 100755 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -26,7 +26,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -func NewMigrator(dm *engine.DataManager, dataDBType, dataDBEncoding string, storDB engine.Storage, storDBType string, oldDataDB V1DataDB, oldDataDBType, oldDataDBEncoding string, oldStorDB engine.Storage, oldStorDBType string, dryRun bool) (m *Migrator, err error) { +func NewMigrator(dmIN *engine.DataManager, dmOut *engine.DataManager, dataDBType, dataDBEncoding string, storDB engine.Storage, storDBType string, oldDataDB MigratorDataDB, oldDataDBType, oldDataDBEncoding string, oldStorDB engine.Storage, oldStorDBType string, dryRun bool, sameDBname bool) (m *Migrator, err error) { var mrshlr engine.Marshaler var oldmrshlr engine.Marshaler if dataDBEncoding == utils.MSGPACK { @@ -41,27 +41,30 @@ func NewMigrator(dm *engine.DataManager, dataDBType, dataDBEncoding string, stor stats := make(map[string]int) m = &Migrator{ - dm: dm, dataDBType: dataDBType, - storDB: storDB, storDBType: storDBType, mrshlr: mrshlr, + dmOut: dmOut, dataDBType: dataDBType, + storDB: storDB, storDBType: storDBType, + mrshlr: mrshlr, dmIN: dmIN, oldDataDB: oldDataDB, oldDataDBType: oldDataDBType, oldStorDB: oldStorDB, oldStorDBType: oldStorDBType, - oldmrshlr: oldmrshlr, dryRun: dryRun, stats: stats, + oldmrshlr: oldmrshlr, dryRun: dryRun, sameDBname: sameDBname, stats: stats, } return m, err } type Migrator struct { - dm *engine.DataManager + dmIN *engine.DataManager //oldatadb + dmOut *engine.DataManager dataDBType string storDB engine.Storage storDBType string mrshlr engine.Marshaler - oldDataDB V1DataDB + oldDataDB MigratorDataDB oldDataDBType string oldStorDB engine.Storage oldStorDBType string oldmrshlr engine.Marshaler dryRun bool + sameDBname bool stats map[string]int } @@ -84,7 +87,7 @@ func (m *Migrator) Migrate(taskIDs []string) (err error, stats map[string]int) { err.Error(), fmt.Sprintf("error: <%s> when updating CostDetails version into StorDB", err.Error())), nil } - if err := m.dm.DataDB().SetVersions(engine.CurrentDBVersions(m.dataDBType), true); err != nil { + if err := m.dmOut.DataDB().SetVersions(engine.CurrentDBVersions(m.dataDBType), true); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -108,7 +111,224 @@ func (m *Migrator) Migrate(taskIDs []string) (err error, stats map[string]int) { case utils.MetaStats: err = m.migrateStats() case utils.MetaThresholds: - err = m.migrateStats() + err = m.migrateThresholds() + //only Move + case utils.MetaRatingPlans: + err = m.migrateRatingPlans() + case utils.MetaRatingProfile: + err = m.migrateRatingProfiles() + case utils.MetaDestinations: + err = m.migrateDestinations() + case utils.MetaReverseDestinations: + err = m.migrateReverseDestinations() + case utils.MetaLCR: + err = m.migrateLCR() + case utils.MetaCdrStats: + err = m.migrateCdrStats() + case utils.MetaTiming: + err = m.migrateTimings() + case utils.MetaRQF: + err = m.migrateRequestFilter() + case utils.MetaResource: + err = m.migrateResources() + case utils.MetaReverseAlias: + err = m.migrateReverseAlias() + case utils.MetaAlias: + err = m.migrateAlias() + case utils.MetaUser: + err = m.migrateUser() + case utils.MetaSubscribers: + err = m.migrateSubscribers() + case utils.MetaDerivedChargersV: + err = m.migrateDerivedChargers() + //TPS + case utils.MetaTpRatingPlans: + err = m.migrateTPratingplans() + case utils.MetaTpLcrs: + err = m.migrateTPlcrs() + case utils.MetaTpFilters: + err = m.migrateTPfilters() + case utils.MetaTpDestinationRates: + err = m.migrateTPdestinationrates() + case utils.MetaTpActionTriggers: + err = m.migrateTPactiontriggers() + case utils.MetaTpAccountActions: + err = m.migrateTPaccountacction() + case utils.MetaTpActionPlans: + err = m.migrateTPactionplans() + case utils.MetaTpActions: + err = m.migrateTPactions() + case utils.MetaTpDerivedCharges: + err = m.migrateTPderivedchargers() + case utils.MetaTpThresholds: + err = m.migrateTPthresholds() + case utils.MetaTpStats: + err = m.migrateTPstats() + case utils.MetaTpSharedGroups: + err = m.migrateTPsharedgroups() + case utils.MetaTpRatingProfiles: + err = m.migrateTPratingprofiles() + case utils.MetaTpResources: + err = m.migrateTPresources() + case utils.MetaTpRates: + err = m.migrateTPrates() + case utils.MetaTpTiming: + err = m.migrateTpTimings() + case utils.MetaTpAliases: + err = m.migrateTPaliases() + case utils.MetaTpUsers: + err = m.migrateTPusers() + case utils.MetaTpDerivedChargersV: + err = m.migrateTPderivedchargers() + case utils.MetaTpCdrStats: + err = m.migrateTPcdrstats() + case utils.MetaTpDestinations: + err = m.migrateTPDestinations() + case utils.MetaTpRatingPlan: + err = m.migrateTPratingplans() + case utils.MetaTpRatingProfile: + err = m.migrateTPfilters() + //DATADB ALL + case utils.MetaDataDB: + if err = m.migrateCostDetails(); err != nil { + log.Print(err) + } + if err := m.migrateAccounts(); err != nil { + log.Print(err) + } + if err := m.migrateActionPlans(); err != nil { + log.Print(err) + } + if err := m.migrateActionTriggers(); err != nil { + log.Print(err) + } + if err := m.migrateActions(); err != nil { + log.Print(err) + } + if err := m.migrateSharedGroups(); err != nil { + log.Print(err) + } + if err := m.migrateStats(); err != nil { + log.Print(err) + } + if err := m.migrateThresholds(); err != nil { + log.Print(err) + } + if err := m.migrateRatingPlans(); err != nil { + log.Print(err) + } + if err := m.migrateRatingProfiles(); err != nil { + log.Print(err) + } + if err := m.migrateDestinations(); err != nil { + log.Print(err) + } + if err := m.migrateReverseDestinations(); err != nil { + log.Print(err) + } + if err := m.migrateLCR(); err != nil { + log.Print(err) + } + if err := m.migrateCdrStats(); err != nil { + log.Print(err) + } + if err := m.migrateTimings(); err != nil { + log.Print(err) + } + if err := m.migrateRequestFilter(); err != nil { + log.Print(err) + } + if err := m.migrateResources(); err != nil { + log.Print(err) + } + if err := m.migrateReverseAlias(); err != nil { + log.Print(err) + } + if err := m.migrateAlias(); err != nil { + log.Print(err) + } + if err := m.migrateUser(); err != nil { + log.Print(err) + } + if err := m.migrateSubscribers(); err != nil { + log.Print(err) + } + if err := m.migrateDerivedChargers(); err != nil { + log.Print(err) + } + err = nil + //STORDB ALL + case utils.MetaStorDB: + if err := m.migrateTPratingplans(); err != nil { + log.Print(err) + } + if err := m.migrateTPlcrs(); err != nil { + log.Print(err) + } + if err := m.migrateTPfilters(); err != nil { + log.Print(err) + } + if err := m.migrateTPdestinationrates(); err != nil { + log.Print(err) + } + if err := m.migrateTPactiontriggers(); err != nil { + log.Print(err) + } + if err := m.migrateTPaccountacction(); err != nil { + log.Print(err) + } + if err := m.migrateTPactionplans(); err != nil { + log.Print(err) + } + if err := m.migrateTPactions(); err != nil { + log.Print(err) + } + if err := m.migrateTPderivedchargers(); err != nil { + log.Print(err) + } + if err := m.migrateTPthresholds(); err != nil { + log.Print(err) + } + if err := m.migrateTPstats(); err != nil { + log.Print(err) + } + if err := m.migrateTPsharedgroups(); err != nil { + log.Print(err) + } + if err := m.migrateTPratingprofiles(); err != nil { + log.Print(err) + } + if err := m.migrateTPresources(); err != nil { + log.Print(err) + } + if err := m.migrateTPrates(); err != nil { + log.Print(err) + } + if err := m.migrateTpTimings(); err != nil { + log.Print(err) + } + if err := m.migrateTPaliases(); err != nil { + log.Print(err) + } + if err := m.migrateTPusers(); err != nil { + log.Print(err) + } + if err := m.migrateTPderivedchargers(); err != nil { + log.Print(err) + } + if err := m.migrateTPcdrstats(); err != nil { + log.Print(err) + } + if err := m.migrateTPDestinations(); err != nil { + log.Print(err) + } + if err := m.migrateTPratingplans(); err != nil { + log.Print(err) + } + if err := m.migrateTPfilters(); err != nil { + log.Print(err) + } + err = nil } } for k, v := range m.stats { diff --git a/migrator/v1datadb.go b/migrator/migratorDataDB.go similarity index 97% rename from migrator/v1datadb.go rename to migrator/migratorDataDB.go index 9719472fd..f0cc18acb 100644 --- a/migrator/v1datadb.go +++ b/migrator/migratorDataDB.go @@ -18,7 +18,7 @@ along with this program. If not, see package migrator -type V1DataDB interface { +type MigratorDataDB interface { getKeysForPrefix(prefix string) ([]string, error) getv1Account() (v1Acnt *v1Account, err error) setV1Account(x *v1Account) (err error) diff --git a/migrator/migrator_it_test.go b/migrator/migrator_it_test.go index f4a0aa13a..a33eded24 100644 --- a/migrator/migrator_it_test.go +++ b/migrator/migrator_it_test.go @@ -30,6 +30,7 @@ import ( ) var ( + Move = "move" dbtype string mig *Migrator dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here") @@ -45,6 +46,7 @@ var sTestsITMigrator = []func(t *testing.T){ testMigratorActions, testMigratorSharedGroups, testMigratorStats, + testMigratorTPRatingProfile, testFlush, } @@ -58,6 +60,10 @@ func TestMigratorITPostgresConnect(t *testing.T) { if err != nil { log.Fatal(err) } + dataDB2, err := engine.ConfigureDataStorage(postgresITCfg.DataDbType, postgresITCfg.DataDbHost, postgresITCfg.DataDbPort, postgresITCfg.DataDbName, postgresITCfg.DataDbUser, postgresITCfg.DataDbPass, postgresITCfg.DBDataEncoding, postgresITCfg.CacheConfig, *loadHistorySize) + if err != nil { + log.Fatal(err) + } oldDataDB, err := ConfigureV1DataStorage(postgresITCfg.DataDbType, postgresITCfg.DataDbHost, postgresITCfg.DataDbPort, postgresITCfg.DataDbName, postgresITCfg.DataDbUser, postgresITCfg.DataDbPass, postgresITCfg.DBDataEncoding) if err != nil { log.Fatal(err) @@ -72,7 +78,7 @@ func TestMigratorITPostgresConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, storDB, postgresITCfg.StorDBType, oldDataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, oldstorDB, postgresITCfg.StorDBType, false) + mig, err = NewMigrator(dataDB, dataDB2, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, storDB, postgresITCfg.StorDBType, oldDataDB, postgresITCfg.DataDbType, postgresITCfg.DBDataEncoding, oldstorDB, postgresITCfg.StorDBType, false, true) if err != nil { log.Fatal(err) } @@ -96,6 +102,10 @@ func TestMigratorITRedisConnect(t *testing.T) { if err != nil { log.Fatal(err) } + dataDB2, err := engine.ConfigureDataStorage(mysqlITCfg.DataDbType, mysqlITCfg.DataDbHost, mysqlITCfg.DataDbPort, mysqlITCfg.DataDbName, mysqlITCfg.DataDbUser, mysqlITCfg.DataDbPass, mysqlITCfg.DBDataEncoding, mysqlITCfg.CacheConfig, *loadHistorySize) + if err != nil { + log.Fatal(err) + } oldDataDB, err := ConfigureV1DataStorage(mysqlITCfg.DataDbType, mysqlITCfg.DataDbHost, mysqlITCfg.DataDbPort, mysqlITCfg.DataDbName, mysqlITCfg.DataDbUser, mysqlITCfg.DataDbPass, mysqlITCfg.DBDataEncoding) if err != nil { log.Fatal(err) @@ -110,7 +120,7 @@ func TestMigratorITRedisConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, storDB, mysqlITCfg.StorDBType, oldDataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, oldstorDB, mysqlITCfg.StorDBType, false) + mig, err = NewMigrator(dataDB, dataDB2, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, storDB, mysqlITCfg.StorDBType, oldDataDB, mysqlITCfg.DataDbType, mysqlITCfg.DBDataEncoding, oldstorDB, mysqlITCfg.StorDBType, false, true) if err != nil { log.Fatal(err) } @@ -134,6 +144,10 @@ func TestMigratorITMongoConnect(t *testing.T) { if err != nil { log.Fatal(err) } + dataDB2, err := engine.ConfigureDataStorage(mgoITCfg.DataDbType, mgoITCfg.DataDbHost, mgoITCfg.DataDbPort, mgoITCfg.DataDbName, mgoITCfg.DataDbUser, mgoITCfg.DataDbPass, mgoITCfg.DBDataEncoding, mgoITCfg.CacheConfig, *loadHistorySize) + if err != nil { + log.Fatal(err) + } oldDataDB, err := ConfigureV1DataStorage(mgoITCfg.DataDbType, mgoITCfg.DataDbHost, mgoITCfg.DataDbPort, mgoITCfg.DataDbName, mgoITCfg.DataDbUser, mgoITCfg.DataDbPass, mgoITCfg.DBDataEncoding) if err != nil { log.Fatal(err) @@ -148,7 +162,7 @@ func TestMigratorITMongoConnect(t *testing.T) { if err != nil { log.Fatal(err) } - mig, err = NewMigrator(dataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, storDB, mgoITCfg.StorDBType, oldDataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, oldstorDB, mgoITCfg.StorDBType, false) + mig, err = NewMigrator(dataDB, dataDB2, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, storDB, mgoITCfg.StorDBType, oldDataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, oldstorDB, mgoITCfg.StorDBType, false, true) if err != nil { log.Fatal(err) } @@ -162,9 +176,56 @@ func TestMigratorITMongo(t *testing.T) { } } +func TestMigratorITMoveConnect(t *testing.T) { + cdrsMongoCfgPath := path.Join(*dataDir, "conf", "samples", "tutmongo") + mgoITCfg, err := config.NewCGRConfigFromFolder(cdrsMongoCfgPath) + if err != nil { + t.Fatal(err) + } + cdrsMysqlCfgPath := path.Join(*dataDir, "conf", "samples", "tutmysql") + mysqlITCfg, err := config.NewCGRConfigFromFolder(cdrsMysqlCfgPath) + if err != nil { + t.Fatal(err) + } + dataDB, err := engine.ConfigureDataStorage(mgoITCfg.DataDbType, mgoITCfg.DataDbHost, mgoITCfg.DataDbPort, mgoITCfg.DataDbName, mgoITCfg.DataDbUser, mgoITCfg.DataDbPass, mgoITCfg.DBDataEncoding, mgoITCfg.CacheConfig, *loadHistorySize) + if err != nil { + log.Fatal(err) + } + dataDB2, err := engine.ConfigureDataStorage(mysqlITCfg.DataDbType, mysqlITCfg.DataDbHost, mysqlITCfg.DataDbPort, mysqlITCfg.DataDbName, mysqlITCfg.DataDbUser, mysqlITCfg.DataDbPass, mysqlITCfg.DBDataEncoding, mysqlITCfg.CacheConfig, *loadHistorySize) + if err != nil { + log.Fatal(err) + } + oldDataDB, err := ConfigureV1DataStorage(mysqlITCfg.DataDbType, mysqlITCfg.DataDbHost, mysqlITCfg.DataDbPort, mysqlITCfg.DataDbName, mysqlITCfg.DataDbUser, mysqlITCfg.DataDbPass, mysqlITCfg.DBDataEncoding) + if err != nil { + log.Fatal(err) + } + storDB, err := engine.ConfigureStorStorage(mgoITCfg.StorDBType, mgoITCfg.StorDBHost, mgoITCfg.StorDBPort, mgoITCfg.StorDBName, mgoITCfg.StorDBUser, mgoITCfg.StorDBPass, mgoITCfg.DBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + if err != nil { + log.Fatal(err) + } + oldstorDB, err := engine.ConfigureStorStorage(mysqlITCfg.StorDBType, mysqlITCfg.StorDBHost, mysqlITCfg.StorDBPort, mysqlITCfg.StorDBName, mysqlITCfg.StorDBUser, mysqlITCfg.StorDBPass, mysqlITCfg.DBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + if err != nil { + log.Fatal(err) + } + mig, err = NewMigrator(dataDB2, dataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, storDB, mgoITCfg.StorDBType, oldDataDB, mgoITCfg.DataDbType, mgoITCfg.DBDataEncoding, oldstorDB, mgoITCfg.StorDBType, false, false) + if err != nil { + log.Fatal(err) + } +} + +func TestMigratorITMove(t *testing.T) { + dbtype = Move + log.Print("Move") + for _, stest := range sTestsITMigrator { + t.Run("TestITMigratorOnMongo", stest) + } +} + func testFlush(t *testing.T) { - mig.dm.DataDB().Flush("") - if err := engine.SetDBVersions(mig.dm.DataDB()); err != nil { + mig.dmOut.DataDB().Flush("") + if err := engine.SetDBVersions(mig.dmOut.DataDB()); err != nil { t.Error("Error ", err.Error()) } @@ -184,11 +245,16 @@ func testMigratorAccounts(t *testing.T) { if err != nil { t.Error("Error when setting v1 acc ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaAccounts}) if err != nil { t.Error("Error when migrating accounts ", err.Error()) } - result, err := mig.dm.DataDB().GetAccount(testAccount.ID) + result, err := mig.dmOut.DataDB().GetAccount(testAccount.ID) if err != nil { t.Error("Error when getting account ", err.Error()) } @@ -202,17 +268,42 @@ func testMigratorAccounts(t *testing.T) { if err != nil { t.Error("Error when marshaling ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaAccounts}) if err != nil { t.Error("Error when migrating accounts ", err.Error()) } - result, err := mig.dm.DataDB().GetAccount(testAccount.ID) + result, err := mig.dmOut.DataDB().GetAccount(testAccount.ID) if err != nil { t.Error("Error when getting account ", err.Error()) } if !reflect.DeepEqual(testAccount, result) { t.Errorf("Expecting: %+v, received: %+v", testAccount, result) } + case dbtype == Move: + if err := mig.dmIN.DataDB().SetAccount(testAccount); err != nil { + log.Print("GOT ERR DMIN", err) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaAccounts}) + if err != nil { + t.Error("Error when migrating accounts ", err.Error()) + } + result, err := mig.dmOut.DataDB().GetAccount(testAccount.ID) + if err != nil { + log.Print("GOT ERR DMOUT", err) + } + if !reflect.DeepEqual(testAccount, result) { + t.Errorf("Expecting: %+v, received: %+v", testAccount, result) + } } } @@ -225,11 +316,16 @@ func testMigratorActionPlans(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionPlan ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 1, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaActionPlans}) if err != nil { t.Error("Error when migrating ActionPlans ", err.Error()) } - result, err := mig.dm.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) + result, err := mig.dmOut.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionPlan ", err.Error()) } @@ -245,11 +341,40 @@ func testMigratorActionPlans(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionPlans ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 1, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaActionPlans}) if err != nil { t.Error("Error when migrating ActionPlans ", err.Error()) } - result, err := mig.dm.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) + result, err := mig.dmOut.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting ActionPlan ", err.Error()) + } + if ap.Id != result.Id || !reflect.DeepEqual(ap.AccountIDs, result.AccountIDs) { + t.Errorf("Expecting: %+v, received: %+v", *ap, result) + } else if !reflect.DeepEqual(ap.ActionTimings[0].Timing, result.ActionTimings[0].Timing) { + t.Errorf("Expecting: %+v, received: %+v", ap.ActionTimings[0].Timing, result.ActionTimings[0].Timing) + } else if ap.ActionTimings[0].Weight != result.ActionTimings[0].Weight || ap.ActionTimings[0].ActionsID != result.ActionTimings[0].ActionsID { + t.Errorf("Expecting: %+v, received: %+v", ap.ActionTimings[0].Weight, result.ActionTimings[0].Weight) + } + case dbtype == Move: + if err := mig.dmIN.DataDB().SetActionPlan(ap.Id, ap, true, utils.NonTransactional); err != nil { + t.Error("Error when setting ActionPlan ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaActionPlans}) + if err != nil { + t.Error("Error when migrating ActionPlans ", err.Error()) + } + result, err := mig.dmOut.DataDB().GetActionPlan(ap.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionPlan ", err.Error()) } @@ -301,11 +426,16 @@ func testMigratorActionTriggers(t *testing.T) { if err != nil { t.Error("Error when setting v1 ActionTriggers ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 1, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaActionTriggers}) if err != nil { t.Error("Error when migrating ActionTriggers ", err.Error()) } - result, err := mig.dm.GetActionTriggers((*v1atrs)[0].Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetActionTriggers((*v1atrs)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting ActionTriggers ", err.Error()) } @@ -378,6 +508,86 @@ func testMigratorActionTriggers(t *testing.T) { t.Error("Error when migrating ActionTriggers ", err.Error()) } + case dbtype == Move: + if err := mig.dmIN.SetActionTriggers(atrs[0].ID, atrs, utils.NonTransactional); err != nil { + t.Error("Error when setting ActionPlan ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaActionTriggers}) + if err != nil { + t.Error("Error when migrating ActionPlans ", err.Error()) + } + result, err := mig.dmOut.GetActionTriggers(atrs[0].ID, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting ActionTriggers ", err.Error()) + } + if !reflect.DeepEqual(atrs[0].ID, result[0].ID) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ID, result[0].ID) + } else if !reflect.DeepEqual(atrs[0].UniqueID, result[0].UniqueID) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].UniqueID, result[0].UniqueID) + } else if !reflect.DeepEqual(atrs[0].ThresholdType, result[0].ThresholdType) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ThresholdType, result[0].ThresholdType) + } else if !reflect.DeepEqual(atrs[0].ThresholdValue, result[0].ThresholdValue) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ThresholdValue, result[0].ThresholdValue) + } else if !reflect.DeepEqual(atrs[0].Recurrent, result[0].Recurrent) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Recurrent, result[0].Recurrent) + } else if !reflect.DeepEqual(atrs[0].MinSleep, result[0].MinSleep) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].MinSleep, result[0].MinSleep) + } else if !reflect.DeepEqual(atrs[0].ExpirationDate, result[0].ExpirationDate) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ExpirationDate, result[0].ExpirationDate) + } else if !reflect.DeepEqual(atrs[0].ActivationDate, result[0].ActivationDate) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ActivationDate, result[0].ActivationDate) + } else if !reflect.DeepEqual(atrs[0].Balance.Type, result[0].Balance.Type) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Type, result[0].Balance.Type) + } else if !reflect.DeepEqual(atrs[0].Weight, result[0].Weight) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Weight, result[0].Weight) + } else if !reflect.DeepEqual(atrs[0].ActionsID, result[0].ActionsID) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].ActionsID, result[0].ActionsID) + } else if !reflect.DeepEqual(atrs[0].MinQueuedItems, result[0].MinQueuedItems) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].MinQueuedItems, result[0].MinQueuedItems) + } else if !reflect.DeepEqual(atrs[0].Executed, result[0].Executed) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Executed, result[0].Executed) + } else if !reflect.DeepEqual(atrs[0].LastExecutionTime, result[0].LastExecutionTime) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].LastExecutionTime, result[0].LastExecutionTime) + } + //Testing each field of balance + if !reflect.DeepEqual(atrs[0].Balance.Uuid, result[0].Balance.Uuid) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Uuid, result[0].Balance.Uuid) + } else if !reflect.DeepEqual(atrs[0].Balance.ID, result[0].Balance.ID) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.ID, result[0].Balance.ID) + } else if !reflect.DeepEqual(atrs[0].Balance.Type, result[0].Balance.Type) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Type, result[0].Balance.Type) + } else if !reflect.DeepEqual(atrs[0].Balance.Value, result[0].Balance.Value) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Value, result[0].Balance.Value) + } else if !reflect.DeepEqual(atrs[0].Balance.Directions, result[0].Balance.Directions) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Directions, result[0].Balance.Directions) + } else if !reflect.DeepEqual(atrs[0].Balance.ExpirationDate, result[0].Balance.ExpirationDate) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.ExpirationDate, result[0].Balance.ExpirationDate) + } else if !reflect.DeepEqual(atrs[0].Balance.Weight, result[0].Balance.Weight) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Weight, result[0].Balance.Weight) + } else if !reflect.DeepEqual(atrs[0].Balance.DestinationIDs, result[0].Balance.DestinationIDs) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.DestinationIDs, result[0].Balance.DestinationIDs) + } else if !reflect.DeepEqual(atrs[0].Balance.RatingSubject, result[0].Balance.RatingSubject) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.RatingSubject, result[0].Balance.RatingSubject) + } else if !reflect.DeepEqual(atrs[0].Balance.Categories, result[0].Balance.Categories) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Categories, result[0].Balance.Categories) + } else if !reflect.DeepEqual(atrs[0].Balance.SharedGroups, result[0].Balance.SharedGroups) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.SharedGroups, result[0].Balance.SharedGroups) + } else if !reflect.DeepEqual(atrs[0].Balance.TimingIDs, result[0].Balance.TimingIDs) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.TimingIDs, result[0].Balance.TimingIDs) + } else if !reflect.DeepEqual(atrs[0].Balance.TimingIDs, result[0].Balance.TimingIDs) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Timings, result[0].Balance.Timings) + } else if !reflect.DeepEqual(atrs[0].Balance.Disabled, result[0].Balance.Disabled) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Disabled, result[0].Balance.Disabled) + } else if !reflect.DeepEqual(atrs[0].Balance.Factor, result[0].Balance.Factor) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Factor, result[0].Balance.Factor) + } else if !reflect.DeepEqual(atrs[0].Balance.Blocker, result[0].Balance.Blocker) { + t.Errorf("Expecting: %+v, received: %+v", atrs[0].Balance.Blocker, result[0].Balance.Blocker) + } } } @@ -390,11 +600,16 @@ func testMigratorActions(t *testing.T) { if err != nil { t.Error("Error when setting v1 Actions ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 1, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaActions}) if err != nil { t.Error("Error when migrating Actions ", err.Error()) } - result, err := mig.dm.GetActions((*v1act)[0].Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetActions((*v1act)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Actions ", err.Error()) } @@ -407,17 +622,42 @@ func testMigratorActions(t *testing.T) { if err != nil { t.Error("Error when setting v1 Actions ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 1, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaActions}) if err != nil { t.Error("Error when migrating Actions ", err.Error()) } - result, err := mig.dm.GetActions((*v1act)[0].Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetActions((*v1act)[0].Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Actions ", err.Error()) } if !reflect.DeepEqual(*act, result) { t.Errorf("Expecting: %+v, received: %+v", *act, result) } + case dbtype == Move: + if err := mig.dmIN.SetActions((*v1act)[0].Id, *act, utils.NonTransactional); err != nil { + t.Error("Error when setting ActionPlan ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaActions}) + if err != nil { + t.Error("Error when migrating ActionPlans ", err.Error()) + } + result, err := mig.dmOut.GetActions((*v1act)[0].Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting ActionPlan ", err.Error()) + } + if !reflect.DeepEqual(*act, result) { + t.Errorf("Expecting: %+v, received: %+v", *act, result) + } } } @@ -442,11 +682,16 @@ func testMigratorSharedGroups(t *testing.T) { if err != nil { t.Error("Error when setting v1 SharedGroup ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 1} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaSharedGroups}) if err != nil { t.Error("Error when migrating SharedGroup ", err.Error()) } - result, err := mig.dm.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting SharedGroup ", err.Error()) } @@ -458,18 +703,42 @@ func testMigratorSharedGroups(t *testing.T) { if err != nil { t.Error("Error when setting v1 SharedGroup ", err.Error()) } + currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 1} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } err, _ = mig.Migrate([]string{utils.MetaSharedGroups}) if err != nil { t.Error("Error when migrating SharedGroup ", err.Error()) } - result, err := mig.dm.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetSharedGroup(v1sqp.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting SharedGroup ", err.Error()) + } + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) + } + case dbtype == Move: + if err := mig.dmIN.SetSharedGroup(sqp, utils.NonTransactional); err != nil { + t.Error("Error when setting SharedGroup ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaSharedGroups}) + if err != nil { + t.Error("Error when migrating SharedGroup ", err.Error()) + } + result, err := mig.dmOut.GetSharedGroup(sqp.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting SharedGroup ", err.Error()) } if !reflect.DeepEqual(sqp, result) { t.Errorf("Expecting: %+v, received: %+v", sqp, result) } - } } @@ -557,13 +826,12 @@ func testMigratorStats(t *testing.T) { } switch { case dbtype == utils.REDIS: - err := mig.oldDataDB.setV1Stats(v1Sts) if err != nil { t.Error("Error when setting v1Stat ", err.Error()) } - currentVersion := engine.Versions{utils.StatS: 1, utils.Thresholds: 1, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} - err = mig.dm.DataDB().SetVersions(currentVersion, false) + currentVersion := engine.Versions{utils.StatS: 1, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) if err != nil { t.Error("Error when setting version for stats ", err.Error()) } @@ -571,68 +839,7 @@ func testMigratorStats(t *testing.T) { if err != nil { t.Error("Error when migrating Stats ", err.Error()) } - - result, err := mig.dm.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) - if err != nil { - t.Error("Error when getting Stats ", err.Error()) - } - - if !reflect.DeepEqual(sqp.Tenant, result.Tenant) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Tenant, result.Tenant) - } - if !reflect.DeepEqual(sqp.ID, result.ID) { - t.Errorf("Expecting: %+v, received: %+v", sqp.ID, result.ID) - } - if !reflect.DeepEqual(sqp.FilterIDs, result.FilterIDs) { - t.Errorf("Expecting: %+v, received: %+v", sqp.FilterIDs, result.FilterIDs) - } - if !reflect.DeepEqual(sqp.QueueLength, result.QueueLength) { - t.Errorf("Expecting: %+v, received: %+v", sqp.QueueLength, result.QueueLength) - } - if !reflect.DeepEqual(sqp.TTL, result.TTL) { - t.Errorf("Expecting: %+v, received: %+v", sqp.TTL, result.TTL) - } - if !reflect.DeepEqual(sqp.Metrics, result.Metrics) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Metrics, result.Metrics) - } - if !reflect.DeepEqual(sqp.Thresholds, result.Thresholds) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Thresholds, result.Thresholds) - } - if !reflect.DeepEqual(sqp.Blocker, result.Blocker) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Blocker, result.Blocker) - } - if !reflect.DeepEqual(sqp.Stored, result.Stored) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Stored, result.Stored) - } - if !reflect.DeepEqual(sqp.Weight, result.Weight) { - t.Errorf("Expecting: %+v, received: %+v", sqp.Weight, result.Weight) - } - if !reflect.DeepEqual(sqp, result) { - t.Errorf("Expecting: %+v, received: %+v", sqp, result) - } - result1, err := mig.dm.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) - if err != nil { - t.Error("Error when getting Stats ", err.Error()) - } - if !reflect.DeepEqual(filter, result1) { - t.Errorf("Expecting: %+v, received: %+v", filter, result1) - } - - case dbtype == utils.MONGO: - err := mig.oldDataDB.setV1Stats(v1Sts) - if err != nil { - t.Error("Error when setting v1Stat ", err.Error()) - } - currentVersion := engine.Versions{utils.StatS: 1, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} - err = mig.dm.DataDB().SetVersions(currentVersion, false) - if err != nil { - t.Error("Error when setting version for stats ", err.Error()) - } - err, _ = mig.Migrate([]string{utils.MetaStats}) - if err != nil { - t.Error("Error when migrating Stats ", err.Error()) - } - result, err := mig.dm.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + result, err := mig.dmOut.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Stats ", err.Error()) } @@ -669,7 +876,7 @@ func testMigratorStats(t *testing.T) { if !reflect.DeepEqual(sqp, result) { t.Errorf("Expecting: %+v, received: %+v", sqp, result) } - result1, err := mig.dm.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + result1, err := mig.dmOut.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) if err != nil { t.Error("Error when getting Stats ", err.Error()) } @@ -679,11 +886,158 @@ func testMigratorStats(t *testing.T) { if !reflect.DeepEqual(filter.Tenant, result1.Tenant) { t.Errorf("Expecting: %+v, received: %+v", filter.Tenant, result1.Tenant) } - } - result1, err := mig.dm.GetStatQueue("cgrates.org", v1Sts.Id, true, utils.NonTransactional) - if err != nil { - t.Error("Error when getting Stats ", err.Error()) - } - log.Print("Wrong version", result1) + result2, err := mig.dmOut.GetStatQueue("cgrates.org", sq.ID, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(sq.ID, result2.ID) { + t.Errorf("Expecting: %+v, received: %+v", sq.ID, result2.ID) + } + case dbtype == utils.MONGO: + err := mig.oldDataDB.setV1Stats(v1Sts) + if err != nil { + t.Error("Error when setting v1Stat ", err.Error()) + } + currentVersion := engine.Versions{utils.StatS: 1, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2} + err = mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaStats}) + if err != nil { + t.Error("Error when migrating Stats ", err.Error()) + } + result, err := mig.dmOut.GetStatQueueProfile("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(sqp.Tenant, result.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Tenant, result.Tenant) + } + if !reflect.DeepEqual(sqp.ID, result.ID) { + t.Errorf("Expecting: %+v, received: %+v", sqp.ID, result.ID) + } + if !reflect.DeepEqual(sqp.FilterIDs, result.FilterIDs) { + t.Errorf("Expecting: %+v, received: %+v", sqp.FilterIDs, result.FilterIDs) + } + if !reflect.DeepEqual(sqp.QueueLength, result.QueueLength) { + t.Errorf("Expecting: %+v, received: %+v", sqp.QueueLength, result.QueueLength) + } + if !reflect.DeepEqual(sqp.TTL, result.TTL) { + t.Errorf("Expecting: %+v, received: %+v", sqp.TTL, result.TTL) + } + if !reflect.DeepEqual(sqp.Metrics, result.Metrics) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Metrics, result.Metrics) + } + if !reflect.DeepEqual(sqp.Thresholds, result.Thresholds) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Thresholds, result.Thresholds) + } + if !reflect.DeepEqual(sqp.Blocker, result.Blocker) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Blocker, result.Blocker) + } + if !reflect.DeepEqual(sqp.Stored, result.Stored) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Stored, result.Stored) + } + if !reflect.DeepEqual(sqp.Weight, result.Weight) { + t.Errorf("Expecting: %+v, received: %+v", sqp.Weight, result.Weight) + } + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) + } + result1, err := mig.dmOut.GetFilter("cgrates.org", v1Sts.Id, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(filter.ActivationInterval, result1.ActivationInterval) { + t.Errorf("Expecting: %+v, received: %+v", filter.ActivationInterval, result1.ActivationInterval) + } + if !reflect.DeepEqual(filter.Tenant, result1.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", filter.Tenant, result1.Tenant) + } + result2, err := mig.dmOut.GetStatQueue("cgrates.org", sq.ID, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(sq.ID, result2.ID) { + t.Errorf("Expecting: %+v, received: %+v", sq.ID, result2.ID) + } + case dbtype == Move: + if err := mig.dmIN.SetStatQueueProfile(sqp); err != nil { + t.Error("Error when setting Stats ", err.Error()) + } + if err := mig.dmIN.SetStatQueue(sq); err != nil { + t.Error("Error when setting Stats ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaStats}) + if err != nil { + t.Error("Error when migrating Stats ", err.Error()) + } + result, err := mig.dmOut.GetStatQueueProfile(sqp.Tenant, sqp.ID, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + result1, err := mig.dmOut.GetStatQueue(sq.Tenant, sq.ID, true, utils.NonTransactional) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(sqp, result) { + t.Errorf("Expecting: %+v, received: %+v", sqp, result) + } + if !reflect.DeepEqual(sq.ID, result1.ID) { + t.Errorf("Expecting: %+v, received: %+v", sq.ID, result1.ID) + } + } +} + +func testMigratorTPRatingProfile(t *testing.T) { + tpRatingProfile := &utils.TPRatingProfile{ + TPid: "TPRProf1", + LoadId: "RPrf", + Direction: "*out", + Tenant: "Tenant1", + Category: "Category", + Subject: "Subject", + RatingPlanActivations: []*utils.TPRatingActivation{ + &utils.TPRatingActivation{ + ActivationTime: "2014-07-29T15:00:00Z", + RatingPlanId: "PlanOne", + FallbackSubjects: "FallBack", + CdrStatQueueIds: "RandomId", + }, + &utils.TPRatingActivation{ + ActivationTime: "2015-07-29T10:00:00Z", + RatingPlanId: "PlanTwo", + FallbackSubjects: "FallOut", + CdrStatQueueIds: "RandomIdTwo", + }, + }, + } + switch dbtype { + case Move: + if err := mig.InStorDB().SetTPRatingProfiles([]*utils.TPRatingProfile{tpRatingProfile}); err != nil { + t.Error("Error when setting Stats ", err.Error()) + } + currentVersion := engine.CurrentDataDBVersions() + err := mig.dmOut.DataDB().SetVersions(currentVersion, false) + if err != nil { + t.Error("Error when setting version for stats ", err.Error()) + } + err, _ = mig.Migrate([]string{utils.MetaTpRatingProfiles}) + if err != nil { + t.Error("Error when migrating Stats ", err.Error()) + } + result, err := mig.OutStorDB().GetTPRatingProfiles(tpRatingProfile) + if err != nil { + t.Error("Error when getting Stats ", err.Error()) + } + if !reflect.DeepEqual(tpRatingProfile, result[0]) { + t.Errorf("Expecting: %+v, received: %+v", tpRatingProfile, result[0]) + } + } } diff --git a/migrator/rating_plan.go b/migrator/rating_plan.go new file mode 100644 index 000000000..9f0b316fb --- /dev/null +++ b/migrator/rating_plan.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentRatingPlans() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.RATING_PLAN_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.RATING_PLAN_PREFIX) + rp, err := m.dmIN.GetRatingPlan(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if rp != nil { + if m.dryRun != true { + if err := m.dmOut.SetRatingPlan(rp, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateRatingPlans() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.RatingPlan] { + case current[utils.RatingPlan]: + if m.sameDBname { + return + } + if err := m.migrateCurrentRatingPlans(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/rating_profile.go b/migrator/rating_profile.go new file mode 100644 index 000000000..7801f7178 --- /dev/null +++ b/migrator/rating_profile.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentRatingProfiles() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.RATING_PROFILE_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.RATING_PROFILE_PREFIX) + rp, err := m.dmIN.GetRatingProfile(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if rp != nil { + if m.dryRun != true { + if err := m.dmOut.SetRatingProfile(rp, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateRatingProfiles() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.RatingProfile] { + case current[utils.RatingProfile]: + if m.sameDBname { + return + } + if err := m.migrateCurrentRatingProfiles(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/request_filter.go b/migrator/request_filter.go new file mode 100644 index 000000000..c0cda1e89 --- /dev/null +++ b/migrator/request_filter.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentRequestFilter() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix("request_filter_indexes") + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, "request_filter_indexes") + rq, err := m.dmIN.GetReqFilterIndexes(idg) + if err != nil { + return err + } + if rq != nil { + if m.dryRun != true { + if err := m.dmOut.SetReqFilterIndexes(id, rq); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateRequestFilter() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.RQF] { + case current[utils.RQF]: + if m.sameDBname { + return + } + if err := m.migrateCurrentRequestFilter(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/resource.go b/migrator/resource.go new file mode 100644 index 000000000..f55f78484 --- /dev/null +++ b/migrator/resource.go @@ -0,0 +1,80 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentResource() (err error) { + var ids []string + tenant := config.CgrConfig().DefaultTenant + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ResourceProfilesPrefix) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ResourceProfilesPrefix) + res, err := m.dmIN.GetResource(tenant, idg, true, utils.NonTransactional) + if err != nil { + return err + } + if res != nil { + if m.dryRun != true { + if err := m.dmOut.SetResource(res); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateResources() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Resource] { + case current[utils.Resource]: + if m.sameDBname { + return + } + if err := m.migrateCurrentResource(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/sharedgroup.go b/migrator/sharedgroup.go index 8976052d8..47de6cddf 100644 --- a/migrator/sharedgroup.go +++ b/migrator/sharedgroup.go @@ -20,6 +20,7 @@ package migrator import ( "fmt" + "strings" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -31,7 +32,30 @@ type v1SharedGroup struct { MemberIds []string } -func (m *Migrator) migrateSharedGroups() (err error) { +func (m *Migrator) migrateCurrentSharedGroups() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.SHARED_GROUP_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.SHARED_GROUP_PREFIX) + sgs, err := m.dmIN.GetSharedGroup(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if sgs != nil { + if m.dryRun != true { + if err := m.dmOut.SetSharedGroup(sgs, utils.NonTransactional); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV1SharedGroups() (err error) { var v1SG *v1SharedGroup for { v1SG, err = m.oldDataDB.getV1SharedGroup() @@ -44,7 +68,7 @@ func (m *Migrator) migrateSharedGroups() (err error) { if v1SG != nil { acnt := v1SG.AsSharedGroup() if m.dryRun != true { - if err = m.dm.SetSharedGroup(acnt, utils.NonTransactional); err != nil { + if err = m.dmOut.SetSharedGroup(acnt, utils.NonTransactional); err != nil { return err } m.stats[utils.SharedGroups] += 1 @@ -53,7 +77,7 @@ func (m *Migrator) migrateSharedGroups() (err error) { } // All done, update version wtih current one vrs := engine.Versions{utils.SharedGroups: engine.CurrentStorDBVersions()[utils.SharedGroups]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -62,6 +86,39 @@ func (m *Migrator) migrateSharedGroups() (err error) { return } +func (m *Migrator) migrateSharedGroups() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.SharedGroups] { + case current[utils.SharedGroups]: + if m.sameDBname { + return + } + if err := m.migrateCurrentSharedGroups(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1SharedGroups(); err != nil { + return err + } + } + return +} + func (v1SG v1SharedGroup) AsSharedGroup() (sg *engine.SharedGroup) { sg = &engine.SharedGroup{ Id: v1SG.Id, diff --git a/migrator/stats.go b/migrator/stats.go index aad3c4e86..304e3c4f8 100644 --- a/migrator/stats.go +++ b/migrator/stats.go @@ -20,7 +20,6 @@ package migrator import ( "fmt" - "log" "strconv" "strings" "time" @@ -60,30 +59,52 @@ type v1Stat struct { type v1Stats []*v1Stat -func (m *Migrator) migrateStats() (err error) { - var vrs engine.Versions - if m.dm.DataDB() == nil { - return utils.NewCGRError(utils.Migrator, - utils.MandatoryIEMissingCaps, - utils.NoStorDBConnection, - "no connection to datadb") - } - vrs, err = m.dm.DataDB().GetVersions(utils.TBLVersions) +func (m *Migrator) migrateCurrentStats() (err error) { + var ids []string + tenant := config.CgrConfig().DefaultTenant + //StatQueue + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.StatQueuePrefix) if err != nil { - return utils.NewCGRError(utils.Migrator, - utils.ServerErrorCaps, - err.Error(), - fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) - } else if len(vrs) == 0 { - return utils.NewCGRError(utils.Migrator, - utils.MandatoryIEMissingCaps, - utils.UndefinedVersion, - "version number is not defined for Stats model") + return err } - if vrs[utils.StatS] != 1 { // Right now we only support migrating from version 1 - log.Print("Wrong version") - return + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.StatQueuePrefix+tenant+":") + sgs, err := m.dmIN.GetStatQueue(tenant, idg, true, utils.NonTransactional) + if err != nil { + return err + } + if sgs != nil { + if m.dryRun != true { + if err := m.dmOut.SetStatQueue(sgs); err != nil { + return err + } + } + } } + //StatQueueProfile + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.StatQueueProfilePrefix) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.StatQueueProfilePrefix+tenant+":") + sgs, err := m.dmIN.GetStatQueueProfile(tenant, idg, true, utils.NonTransactional) + if err != nil { + return err + } + if sgs != nil { + if m.dryRun != true { + if err := m.dmOut.SetStatQueueProfile(sgs); err != nil { + return err + } + } + } + } + + return +} + +func (m *Migrator) migrateV1CDRSTATS() (err error) { var v1Sts *v1Stat for { v1Sts, err = m.oldDataDB.getV1Stats() @@ -106,14 +127,14 @@ func (m *Migrator) migrateStats() (err error) { if err != nil { return err } - if m.dryRun != true { - if err := m.dm.SetFilter(filter); err != nil { + if !m.dryRun { + if err := m.dmOut.SetFilter(filter); err != nil { return err } - if err := m.dm.SetStatQueue(sq); err != nil { + if err := m.dmOut.SetStatQueue(sq); err != nil { return err } - if err := m.dm.SetStatQueueProfile(sts); err != nil { + if err := m.dmOut.SetStatQueueProfile(sts); err != nil { return err } m.stats[utils.StatS] += 1 @@ -123,7 +144,7 @@ func (m *Migrator) migrateStats() (err error) { if m.dryRun != true { // All done, update version wtih current one vrs := engine.Versions{utils.StatS: engine.CurrentStorDBVersions()[utils.StatS]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -133,6 +154,39 @@ func (m *Migrator) migrateStats() (err error) { return } +func (m *Migrator) migrateStats() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.StatS] { + case current[utils.StatS]: + if m.sameDBname { + return + } + if err := m.migrateCurrentStats(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV1CDRSTATS(); err != nil { + return err + } + } + return +} + func (v1Sts v1Stat) AsStatQP() (filter *engine.Filter, sq *engine.StatQueue, stq *engine.StatQueueProfile, err error) { var filters []*engine.RequestFilter if len(v1Sts.SetupInterval) == 1 { diff --git a/migrator/subscribers.go b/migrator/subscribers.go new file mode 100644 index 000000000..2a4e62ff7 --- /dev/null +++ b/migrator/subscribers.go @@ -0,0 +1,71 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentSubscribers() (err error) { + subs, err := m.dmIN.GetSubscribers() + if err != nil { + return err + } + for id, sub := range subs { + if sub != nil { + if m.dryRun != true { + if err := m.dmOut.SetSubscriber(id, sub); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateSubscribers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Subscribers] { + case current[utils.Subscribers]: + if m.sameDBname { + return + } + if err := m.migrateCurrentSubscribers(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/thresholds.go b/migrator/thresholds.go index d7be759c3..486f29296 100644 --- a/migrator/thresholds.go +++ b/migrator/thresholds.go @@ -20,7 +20,7 @@ package migrator import ( "fmt" - "log" + "strings" "time" "github.com/cgrates/cgrates/config" @@ -29,16 +29,14 @@ import ( ) type v2ActionTrigger struct { - ID string // original csv tag - UniqueID string // individual id - ThresholdType string //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *balance_expired - // stats: *min_asr, *max_asr, *min_acd, *max_acd, *min_tcd, *max_tcd, *min_acc, *max_acc, *min_tcc, *max_tcc, *min_ddc, *max_ddc - ThresholdValue float64 - Recurrent bool // reset excuted flag each run - MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers - ExpirationDate time.Time - ActivationDate time.Time - //BalanceType string // *monetary/*voice etc + ID string // original csv tag + UniqueID string // individual id + ThresholdType string //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *balance_expired + ThresholdValue float64 + Recurrent bool // reset excuted flag each run + MinSleep time.Duration // Minimum duration between two executions in case of recurrent triggers + ExpirationDate time.Time + ActivationDate time.Time Balance *engine.BalanceFilter //filtru Weight float64 ActionsID string @@ -49,30 +47,51 @@ type v2ActionTrigger struct { type v2ActionTriggers []*v2ActionTrigger -func (m *Migrator) migratev1ActionTriggers() (err error) { - var vrs engine.Versions - if m.dm.DataDB() == nil { - return utils.NewCGRError(utils.Migrator, - utils.MandatoryIEMissingCaps, - utils.NoStorDBConnection, - "no connection to datadb") - } - vrs, err = m.dm.DataDB().GetVersions(utils.TBLVersions) +func (m *Migrator) migrateCurrentThresholds() (err error) { + var ids []string + tenant := config.CgrConfig().DefaultTenant + //StatQueue + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ThresholdPrefix) if err != nil { - return utils.NewCGRError(utils.Migrator, - utils.ServerErrorCaps, - err.Error(), - fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) - } else if len(vrs) == 0 { - return utils.NewCGRError(utils.Migrator, - utils.MandatoryIEMissingCaps, - utils.UndefinedVersion, - "version number is not defined for Stats model") + return err } - if vrs[utils.Thresholds] != 1 { // Right now we only support migrating from version 1 - log.Print("Wrong version") - return + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ThresholdPrefix+tenant+":") + ths, err := m.dmIN.GetThreshold(tenant, idg, true, utils.NonTransactional) + if err != nil { + return err + } + if ths != nil { + if m.dryRun != true { + if err := m.dmOut.SetThreshold(ths); err != nil { + return err + } + } + } } + //StatQueueProfile + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.ThresholdProfilePrefix) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.ThresholdProfilePrefix+tenant+":") + ths, err := m.dmIN.GetThresholdProfile(tenant, idg, true, utils.NonTransactional) + if err != nil { + return err + } + if ths != nil { + if m.dryRun != true { + if err := m.dmOut.SetThresholdProfile(ths); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateV2ActionTriggers() (err error) { var v2ACT *v2ActionTrigger for { v2ACT, err = m.oldDataDB.getV2ActionTrigger() @@ -88,13 +107,13 @@ func (m *Migrator) migratev1ActionTriggers() (err error) { return err } if m.dryRun != true { - if err := m.dm.SetFilter(filter); err != nil { + if err := m.dmOut.SetFilter(filter); err != nil { return err } - if err := m.dm.SetThreshold(th); err != nil { + if err := m.dmOut.SetThreshold(th); err != nil { return err } - if err := m.dm.SetThresholdProfile(thp); err != nil { + if err := m.dmOut.SetThresholdProfile(thp); err != nil { return err } m.stats[utils.Thresholds] += 1 @@ -104,7 +123,7 @@ func (m *Migrator) migratev1ActionTriggers() (err error) { if m.dryRun != true { // All done, update version wtih current one vrs := engine.Versions{utils.Thresholds: engine.CurrentStorDBVersions()[utils.Thresholds]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), @@ -113,6 +132,39 @@ func (m *Migrator) migratev1ActionTriggers() (err error) { } return } + +func (m *Migrator) migrateThresholds() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Thresholds] { + case current[utils.Thresholds]: + if m.sameDBname { + return + } + if err := m.migrateCurrentThresholds(); err != nil { + return err + } + return + + case 1: + if err := m.migrateV2ActionTriggers(); err != nil { + return err + } + } + return +} func (v2ATR v2ActionTrigger) AsThreshold() (thp *engine.ThresholdProfile, th *engine.Threshold, filter *engine.Filter, err error) { var filters []*engine.RequestFilter if *v2ATR.Balance.ID != "" { @@ -194,7 +246,7 @@ func (v2ATR v2ActionTrigger) AsThreshold() (thp *engine.ThresholdProfile, th *en func (m *Migrator) SasThreshold(v2ATR *engine.ActionTrigger) (err error) { var vrs engine.Versions - if m.dm.DataDB() == nil { + if m.dmOut.DataDB() == nil { return utils.NewCGRError(utils.Migrator, utils.MandatoryIEMissingCaps, utils.NoStorDBConnection, @@ -206,21 +258,21 @@ func (m *Migrator) SasThreshold(v2ATR *engine.ActionTrigger) (err error) { return err } if filter != nil { - if err := m.dm.SetFilter(filter); err != nil { + if err := m.dmOut.SetFilter(filter); err != nil { return err } } - if err := m.dm.SetThreshold(th); err != nil { + if err := m.dmOut.SetThreshold(th); err != nil { return err } - if err := m.dm.SetThresholdProfile(thp); err != nil { + if err := m.dmOut.SetThresholdProfile(thp); err != nil { return err } m.stats[utils.Thresholds] += 1 } // All done, update version wtih current one vrs = engine.Versions{utils.Thresholds: engine.CurrentStorDBVersions()[utils.Thresholds]} - if err = m.dm.DataDB().SetVersions(vrs, false); err != nil { + if err = m.dmOut.DataDB().SetVersions(vrs, false); err != nil { return utils.NewCGRError(utils.Migrator, utils.ServerErrorCaps, err.Error(), diff --git a/migrator/timings.go b/migrator/timings.go new file mode 100644 index 000000000..0bdc6e9b1 --- /dev/null +++ b/migrator/timings.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTiming() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.TimingsPrefix) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.TimingsPrefix) + tm, err := m.dmIN.GetTiming(idg, true, utils.NonTransactional) + if err != nil { + return err + } + if tm != nil { + if m.dryRun != true { + if err := m.dmOut.SetTiming(tm); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateTimings() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.Timing] { + case current[utils.Timing]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTiming(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_account_actions.go b/migrator/tp_account_actions.go new file mode 100644 index 000000000..a3de0e86b --- /dev/null +++ b/migrator/tp_account_actions.go @@ -0,0 +1,76 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPaccountacction() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPActionTriggers) + if err != nil { + return err + } + + for _, tpid := range tpids { + dest, err := m.InStorDB().GetTPAccountActions(&utils.TPAccountActions{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPAccountActions(dest); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateTPaccountacction() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpAccountActions] { + case current[utils.TpAccountActions]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPaccountacction(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_action_plans.go b/migrator/tp_action_plans.go new file mode 100644 index 000000000..5441d2e37 --- /dev/null +++ b/migrator/tp_action_plans.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPactionplans() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPActionPlans) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPActionPlans, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPActionPlans(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPActionPlans(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPactionplans() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpActionPlans] { + case current[utils.TpActionPlans]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPactionplans(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_action_triggers.go b/migrator/tp_action_triggers.go new file mode 100644 index 000000000..cb83bd6cc --- /dev/null +++ b/migrator/tp_action_triggers.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPactiontriggers() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPActionTriggers) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPActionTriggers, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPActionTriggers(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPActionTriggers(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPactiontriggers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpActionTriggers] { + case current[utils.TpActionTriggers]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPactiontriggers(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_actions.go b/migrator/tp_actions.go new file mode 100644 index 000000000..d5c81d946 --- /dev/null +++ b/migrator/tp_actions.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPactions() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPActions) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPActions, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPActions(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPActions(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPactions() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpActions] { + case current[utils.TpActions]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPactions(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_aliases.go b/migrator/tp_aliases.go new file mode 100644 index 000000000..aabdb251c --- /dev/null +++ b/migrator/tp_aliases.go @@ -0,0 +1,77 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPaliases() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPAliases) + if err != nil { + return err + } + + for _, tpid := range tpids { + dest, err := m.InStorDB().GetTPAliases(&utils.TPAliases{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPAliases(dest); err != nil { + return err + } + } + } + } + + return +} + +func (m *Migrator) migrateTPaliases() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpAliases] { + case current[utils.TpAliases]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPaliases(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_cdr_stats.go b/migrator/tp_cdr_stats.go new file mode 100644 index 000000000..21ee5edb1 --- /dev/null +++ b/migrator/tp_cdr_stats.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPcdrstats() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPCdrStats) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPCdrStats, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPCdrStats(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPCdrStats(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPcdrstats() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpCdrStats] { + case current[utils.TpCdrStats]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPcdrstats(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_derived_chargers.go b/migrator/tp_derived_chargers.go new file mode 100644 index 000000000..3619bf93c --- /dev/null +++ b/migrator/tp_derived_chargers.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPderivedchargers() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPDerivedChargers) + if err != nil { + return err + } + + for _, tpid := range tpids { + + dest, err := m.InStorDB().GetTPDerivedChargers(&utils.TPDerivedChargers{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + + if err := m.OutStorDB().SetTPDerivedChargers(dest); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateTPderivedchargers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpDerivedCharges] { + case current[utils.TpDerivedCharges]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPderivedchargers(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_destination_rates.go b/migrator/tp_destination_rates.go new file mode 100644 index 000000000..3a243e06b --- /dev/null +++ b/migrator/tp_destination_rates.go @@ -0,0 +1,82 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPdestinationrates() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPRatingPlans) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPRatingPlans, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + dest, err := m.InStorDB().GetTPDestinationRates(tpid, id, nil) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPDestinationRates(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPdestinationrates() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpDestinationRates] { + case current[utils.TpDestinationRates]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPdestinationrates(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_destinations.go b/migrator/tp_destinations.go new file mode 100644 index 000000000..4f070d1a0 --- /dev/null +++ b/migrator/tp_destinations.go @@ -0,0 +1,82 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPDestinations() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPDestinations) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPDestinations, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + dest, err := m.InStorDB().GetTPDestinations(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPDestinations(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPDestinations() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpDestinations] { + case current[utils.TpDestinations]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPDestinations(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_filters.go b/migrator/tp_filters.go new file mode 100644 index 000000000..ff718a454 --- /dev/null +++ b/migrator/tp_filters.go @@ -0,0 +1,82 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPfilters() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPFilters) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPFilters, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + dest, err := m.InStorDB().GetTPFilters(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPFilters(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPfilters() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpFilters] { + case current[utils.TpFilters]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPfilters(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_lcrs.go b/migrator/tp_lcrs.go new file mode 100644 index 000000000..7ab8b0d89 --- /dev/null +++ b/migrator/tp_lcrs.go @@ -0,0 +1,76 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPlcrs() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPLcrs) + if err != nil { + return err + } + + for _, tpid := range tpids { + dest, err := m.InStorDB().GetTPLCRs(&utils.TPLcrRules{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPLCRs(dest); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateTPlcrs() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpLcrs] { + case current[utils.TpLcrs]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPcdrstats(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_rates.go b/migrator/tp_rates.go new file mode 100644 index 000000000..682a77ea7 --- /dev/null +++ b/migrator/tp_rates.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPrates() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPDestinations) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPDestinations, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPRates(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPRates(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPrates() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpRates] { + case current[utils.TpRates]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPrates(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_rating_plans.go b/migrator/tp_rating_plans.go new file mode 100644 index 000000000..1ade51e22 --- /dev/null +++ b/migrator/tp_rating_plans.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPratingplans() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPRatingPlans) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPRatingPlans, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + rps, err := m.InStorDB().GetTPRatingPlans(tpid, id, nil) + if err != nil { + return err + } + if rps != nil { + if m.dryRun != true { + if err := m.InStorDB().SetTPRatingPlans(rps); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPratingplans() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpRatingPlans] { + case current[utils.TpRatingPlans]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPratingplans(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_rating_profiles.go b/migrator/tp_rating_profiles.go new file mode 100644 index 000000000..45620492b --- /dev/null +++ b/migrator/tp_rating_profiles.go @@ -0,0 +1,77 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPratingprofiles() (err error) { + + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPRateProfiles) + if err != nil { + return err + } + + for _, tpid := range tpids { + dest, err := m.InStorDB().GetTPRatingProfiles(&utils.TPRatingProfile{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPRatingProfiles(dest); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateTPratingprofiles() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpRatingProfiles] { + case current[utils.TpRatingProfiles]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPratingprofiles(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_resources.go b/migrator/tp_resources.go new file mode 100644 index 000000000..e72bae174 --- /dev/null +++ b/migrator/tp_resources.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPresources() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPResources) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPResources, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPResources(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPResources(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPresources() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpResources] { + case current[utils.TpResources]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPresources(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_shared_groups.go b/migrator/tp_shared_groups.go new file mode 100644 index 000000000..779a72557 --- /dev/null +++ b/migrator/tp_shared_groups.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPsharedgroups() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPSharedGroups) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPSharedGroups, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPSharedGroups(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPSharedGroups(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPsharedgroups() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpSharedGroups] { + case current[utils.TpSharedGroups]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPsharedgroups(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_stats.go b/migrator/tp_stats.go new file mode 100644 index 000000000..7e7d4d605 --- /dev/null +++ b/migrator/tp_stats.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPstats() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPStats) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPStats, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPStats(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPStats(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPstats() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpStats] { + case current[utils.TpStats]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPstats(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_thresholds.go b/migrator/tp_thresholds.go new file mode 100644 index 000000000..3e7be5750 --- /dev/null +++ b/migrator/tp_thresholds.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPthresholds() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPThresholds) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPThresholds, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + dest, err := m.InStorDB().GetTPThresholds(tpid, id) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPThresholds(dest); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTPthresholds() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpThresholds] { + case current[utils.TpThresholds]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPthresholds(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_timings.go b/migrator/tp_timings.go new file mode 100644 index 000000000..30fb8d217 --- /dev/null +++ b/migrator/tp_timings.go @@ -0,0 +1,83 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPTiming() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPTimings) + if err != nil { + return err + } + + for _, tpid := range tpids { + ids, err := m.InStorDB().GetTpTableIds(tpid, utils.TBLTPTimings, utils.TPDistinctIds{}, map[string]string{}, nil) + if err != nil { + return err + } + for _, id := range ids { + + tm, err := m.InStorDB().GetTPTimings(tpid, id) + if err != nil { + return err + } + if tm != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPTimings(tm); err != nil { + return err + } + } + } + } + } + return +} + +func (m *Migrator) migrateTpTimings() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpTiming] { + case current[utils.TpTiming]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPTiming(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/tp_users.go b/migrator/tp_users.go new file mode 100644 index 000000000..0343a7dd3 --- /dev/null +++ b/migrator/tp_users.go @@ -0,0 +1,77 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentTPusers() (err error) { + tpids, err := m.InStorDB().GetTpIds(utils.TBLTPUsers) + if err != nil { + return err + } + + for _, tpid := range tpids { + dest, err := m.InStorDB().GetTPUsers(&utils.TPUsers{TPid: tpid}) + if err != nil { + return err + } + if dest != nil { + if m.dryRun != true { + if err := m.OutStorDB().SetTPUsers(dest); err != nil { + return err + } + } + } + + } + return +} + +func (m *Migrator) migrateTPusers() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.TpUsers] { + case current[utils.TpUsers]: + if m.sameDBname { + return + } + if err := m.migrateCurrentTPusers(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/user.go b/migrator/user.go new file mode 100644 index 000000000..6111b6fce --- /dev/null +++ b/migrator/user.go @@ -0,0 +1,78 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package migrator + +import ( + "fmt" + "strings" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func (m *Migrator) migrateCurrentUser() (err error) { + var ids []string + ids, err = m.dmIN.DataDB().GetKeysForPrefix(utils.USERS_PREFIX) + if err != nil { + return err + } + for _, id := range ids { + idg := strings.TrimPrefix(id, utils.USERS_PREFIX) + usr, err := m.dmIN.GetUser(idg) + if err != nil { + return err + } + if usr != nil { + if m.dryRun != true { + if err := m.dmOut.SetUser(usr); err != nil { + return err + } + } + } + } + return +} + +func (m *Migrator) migrateUser() (err error) { + var vrs engine.Versions + current := engine.CurrentDataDBVersions() + vrs, err = m.dmOut.DataDB().GetVersions(utils.TBLVersions) + if err != nil { + return utils.NewCGRError(utils.Migrator, + utils.ServerErrorCaps, + err.Error(), + fmt.Sprintf("error: <%s> when querying oldDataDB for versions", err.Error())) + } else if len(vrs) == 0 { + return utils.NewCGRError(utils.Migrator, + utils.MandatoryIEMissingCaps, + utils.UndefinedVersion, + "version number is not defined for ActionTriggers model") + } + switch vrs[utils.User] { + case current[utils.User]: + if m.sameDBname { + return + } + if err := m.migrateCurrentUser(); err != nil { + return err + } + return + } + return +} diff --git a/migrator/v1migrator_utils.go b/migrator/v1migrator_utils.go index 3be1e723d..1c99be99e 100644 --- a/migrator/v1migrator_utils.go +++ b/migrator/v1migrator_utils.go @@ -23,11 +23,12 @@ import ( "fmt" "strconv" + "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" ) -func ConfigureV1DataStorage(db_type, host, port, name, user, pass, marshaler string) (db V1DataDB, err error) { - var d V1DataDB +func ConfigureV1DataStorage(db_type, host, port, name, user, pass, marshaler string) (db MigratorDataDB, err error) { + var d MigratorDataDB switch db_type { case utils.REDIS: var db_nb int @@ -42,7 +43,7 @@ func ConfigureV1DataStorage(db_type, host, port, name, user, pass, marshaler str d, err = newv1RedisStorage(host, db_nb, pass, marshaler) case utils.MONGO: d, err = newv1MongoStorage(host, port, name, user, pass, utils.DataDB, nil) - db = d.(V1DataDB) + db = d.(MigratorDataDB) default: err = errors.New(fmt.Sprintf("Unknown db '%s' valid options are '%s' or '%s'", db_type, utils.REDIS, utils.MONGO)) @@ -52,3 +53,11 @@ func ConfigureV1DataStorage(db_type, host, port, name, user, pass, marshaler str } return d, nil } + +func (m *Migrator) InStorDB() engine.LoadStorage { + return m.oldStorDB.(engine.LoadStorage) +} + +func (m *Migrator) OutStorDB() engine.LoadStorage { + return m.storDB.(engine.LoadStorage) +} diff --git a/migrator/v1mongo_data.go b/migrator/v1mongo_data.go index ba0d7b26e..52472a0ba 100644 --- a/migrator/v1mongo_data.go +++ b/migrator/v1mongo_data.go @@ -61,7 +61,7 @@ func newv1MongoStorage(host, port, db, user, pass, storageType string, cdrsIndex v1ms = &v1Mongo{db: db, session: session, v1ms: engine.NewCodecMsgpackMarshaler()} return } - +func (v1ms *v1Mongo) Close() {} func (v1ms *v1Mongo) getKeysForPrefix(prefix string) ([]string, error) { return nil, nil } diff --git a/migrator/v1redis.go b/migrator/v1redis.go index d4764b226..7616cd6cf 100644 --- a/migrator/v1redis.go +++ b/migrator/v1redis.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/guardian" "github.com/cgrates/cgrates/utils" "github.com/mediocregopher/radix.v2/pool" @@ -78,7 +79,7 @@ func (v1rs *v1Redis) cmd(cmd string, args ...interface{}) *redis.Resp { return redis.NewResp(err) } result := c1.Cmd(cmd, args...) - if result.IsType(redis.IOErr) { // Failover mecanism + if result.IsType(redis.IOErr) { // Failover mecaneism utils.Logger.Warning(fmt.Sprintf(" error <%s>, attempting failover.", result.Err.Error())) c2, err := v1rs.dbPool.Get() if err == nil { @@ -92,6 +93,7 @@ func (v1rs *v1Redis) cmd(cmd string, args ...interface{}) *redis.Resp { } return result } +func (v1rs *v1Redis) Close() {} func (v1rs *v1Redis) getKeysForPrefix(prefix string) ([]string, error) { r := v1rs.cmd("KEYS", prefix+"*") @@ -101,6 +103,32 @@ func (v1rs *v1Redis) getKeysForPrefix(prefix string) ([]string, error) { return r.List() } +// Adds a single load instance to load history +func (v1rs *v1Redis) AddLoadHistory(ldInst *utils.LoadInstance, loadHistSize int, transactionID string) error { + if loadHistSize == 0 { // Load history disabled + return nil + } + marshaled, err := v1rs.ms.Marshal(&ldInst) + if err != nil { + return err + } + _, err = guardian.Guardian.Guard(func() (interface{}, error) { // Make sure we do it locked since other instance can modify history while we read it + histLen, err := v1rs.cmd("LLEN", utils.LOADINST_KEY).Int() + if err != nil { + return nil, err + } + if histLen >= loadHistSize { // Have hit maximum history allowed, remove oldest element in order to add new one + if err := v1rs.cmd("RPOP", utils.LOADINST_KEY).Err; err != nil { + return nil, err + } + } + err = v1rs.cmd("LPUSH", utils.LOADINST_KEY, marshaled).Err + return nil, err + }, 0, utils.LOADINST_KEY) + + return err +} + //Account methods //get func (v1rs *v1Redis) getv1Account() (v1Acnt *v1Account, err error) { diff --git a/utils/consts.go b/utils/consts.go index ac8c9f21c..a90d707b3 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -392,19 +392,8 @@ const ( StoppedCaps = "STOPPED" SchedulerNotRunningCaps = "SCHEDULLER_NOT_RUNNING" MetaScheduler = "*scheduler" - MetaCostDetails = "*cost_details" - MetaAccounts = "*accounts" - MetaActionPlans = "*action_plans" - MetaActionTriggers = "*action_triggers" - MetaActions = "*actions" - MetaSharedGroups = "*shared_groups" - MetaStats = "*stats" - MetaThresholds = "*thresholds" - Migrator = "migrator" - UnsupportedMigrationTask = "unsupported migration task" NoStorDBConnection = "not connected to StorDB" UndefinedVersion = "undefined version" - MetaSetVersions = "*set_versions" UnsupportedDB = "unsupported database" ACCOUNT_SUMMARY = "AccountSummary" TxtSuffix = ".txt" @@ -429,13 +418,6 @@ const ( MetaEveryMinute = "*every_minute" MetaHourly = "*hourly" ID = "ID" - MetaASR = "*asr" - MetaACD = "*acd" - MetaTCD = "*tcd" - MetaACC = "*acc" - MetaTCC = "*tcc" - MetaPDD = "*pdd" - MetaDDC = "*ddc" CacheDestinations = "destinations" CacheReverseDestinations = "reverse_destinations" CacheRatingPlans = "rating_plans" @@ -491,13 +473,123 @@ const ( Disabled = "Disabled" Action = "Action" ThresholdSv1ProcessEvent = "ThresholdSv1.ProcessEvent" - MetaNow = "*now" SMGenericV2UpdateSession = "SMGenericV2.UpdateSession" SMGenericV2InitiateSession = "SMGenericV2.InitiateSession" SMGenericV1UpdateSession = "SMGenericV1.UpdateSession" SMGenericV1InitiateSession = "SMGenericV1.InitiateSession" ) +//Meta +const ( + MetaASR = "*asr" + MetaACD = "*acd" + MetaTCD = "*tcd" + MetaACC = "*acc" + MetaTCC = "*tcc" + MetaPDD = "*pdd" + MetaDDC = "*ddc" + MetaNow = "*now" +) + +//Migrator Metas +const ( + MetaSetVersions = "*set_versions" + MetaCostDetails = "*cost_details" + MetaAccounts = "*accounts" + MetaActionPlans = "*action_plans" + MetaActionTriggers = "*action_triggers" + MetaActions = "*actions" + MetaSharedGroups = "*shared_groups" + MetaStats = "*stats" + MetaThresholds = "*thresholds" + MetaRatingPlans = "*ratingplans" + MetaRatingProfile = "*ratingprofile" + MetaDestinations = "*destinations" + MetaReverseDestinations = "*reversedestinations" + MetaLCR = "*lcr" + MetaCdrStats = "*cdrstats" + MetaTiming = "*Timing" + MetaRQF = "*RQF" + MetaResource = "*Resource" + MetaReverseAlias = "*ReverseAlias" + MetaAlias = "*Alias" + MetaUser = "*User" + MetaSubscribers = "*Subscribers" + MetaDerivedChargersV = "*DerivedChargers" + Migrator = "migrator" + UnsupportedMigrationTask = "unsupported migration task" + MetaTpRatingPlans = "*TpRatingPlans" + MetaTpLcrs = "*TpLcrs" + MetaTpFilters = "*TpFilters" + MetaTpDestinationRates = "*TpDestinationRates" + MetaTpActionTriggers = "*TpActionTriggers" + MetaTpAccountActions = "*TpAccountActions" + MetaTpActionPlans = "*TpActionPlans" + MetaTpActions = "*TpActions" + MetaTpDerivedCharges = "*TpDerivedCharges" + MetaTpThresholds = "*TpThresholds" + MetaTpStats = "*TpStats" + MetaTpSharedGroups = "*TpSharedGroups" + MetaTpRatingProfiles = "*TpRatingProfiles" + MetaTpResources = "*TpResources" + MetaTpRates = "*TpRates" + MetaTpTiming = "*TpTiming" + MetaTpResource = "*TpResource" + MetaTpAliases = "*TpAliases" + MetaTpUsers = "*TpUsers" + MetaTpDerivedChargersV = "*TpDerivedChargers" + MetaTpCdrStats = "*TpCdrStats" + MetaTpDestinations = "*TpDestinations" + MetaTpLCR = "*TpLCR" + MetaTpRatingPlan = "*TpRatingPlan" + MetaTpRatingProfile = "*TpRatingProfile" + MetaStorDB = "*StorDB" + MetaDataDB = "*DataDB" +) + +//versions +const ( + TpRatingPlans = "TpRatingPlans" + TpLcrs = "TpLcrs" + TpFilters = "TpFilters" + TpDestinationRates = "TpDestinationRates" + TpActionTriggers = "TpActionTriggers" + TpAccountActions = "TpAccountActions" + TpActionPlans = "TpActionPlans" + TpActions = "TpActions" + TpDerivedCharges = "TpDerivedCharges" + TpThresholds = "TpThresholds" + TpStats = "TpStats" + TpSharedGroups = "TpSharedGroups" + TpRatingProfiles = "TpRatingProfiles" + TpResources = "TpResources" + TpRates = "TpRates" + TpTiming = "TpTiming" + TpResource = "TpResource" + TpAliases = "TpAliases" + TpUsers = "TpUsers" + TpDerivedChargersV = "TpDerivedChargers" + TpCdrStats = "TpCdrStats" + TpDestinations = "TpDestinations" + TpLCR = "TpLCR" + TpRatingPlan = "TpRatingPlan" + TpRatingProfile = "TpRatingProfile" + Timing = "Timing" + RQF = "RQF" + Resource = "Resource" + ReverseAlias = "ReverseAlias" + Alias = "Alias" + User = "User" + Subscribers = "Subscribers" + DerivedChargersV = "DerivedChargers" + CdrStats = "CdrStats" + Destinations = "Destinations" + ReverseDestinations = "ReverseDestinations" + LCR = "LCR" + RatingPlan = "RatingPlan" + RatingProfile = "RatingProfile" +) + func buildCacheInstRevPrefixes() { CachePrefixToInstance = make(map[string]string) for k, v := range CacheInstanceToPrefix { From e204e07e09d67728c772debdf38167ceb307a46a Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Tue, 14 Nov 2017 14:33:26 +0000 Subject: [PATCH 46/75] Fixed typo --- cmd/cgr-migrator/cgr-migrator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index 2b7b8d205..aeb939315 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -31,7 +31,7 @@ import ( ) var ( - sameDBname true + sameDBname = true inDataDB migrator.MigratorDataDB oldstorDB engine.Storage oStorDBType string @@ -133,7 +133,7 @@ func main() { log.Print("Migrating: ", *migrate) } if inDataDBName != outDataDBName { - sameDBname := false + sameDBname = false } m, err := migrator.NewMigrator(dmIN, dmOUT, *outDataDBType, *dbDataEncoding, storDB, *storDBType, inDataDB, *inDataDBType, *inDBDataEncoding, oldstorDB, *oldStorDBType, *dryRun, sameDBname) if err != nil { From 4d093c5511f9a991137dd8ac89f2ad92ebfdc233 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 14 Nov 2017 18:02:20 +0100 Subject: [PATCH 47/75] Displaying Diameter CCA in case of dry_run templates --- agents/dmtagent.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index 29422817c..d6b714a9c 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -202,6 +202,9 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro utils.Logger.Err(fmt.Sprintf(" CCA SetProcessorAVPs for message: %+v, error: %s", ccr.diamMessage, err)) return false, ErrDiameterRatingFailed } + if reqProcessor.DryRun { + utils.Logger.Info(fmt.Sprintf(" CCA message: %s", cca.diamMessage)) + } return true, nil } From bb691b372aea0bc8042c8499220bdd55d939564e Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Wed, 15 Nov 2017 11:40:03 +0000 Subject: [PATCH 48/75] Refactored GetTpids and updated cgr-migrator --- cmd/cgr-migrator/cgr-migrator.go | 50 +++++++++++++-------------- engine/storage_mongo_stordb.go | 42 +++++++++-------------- engine/storage_sql.go | 58 ++++++++++++-------------------- 3 files changed, 61 insertions(+), 89 deletions(-) diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index aeb939315..5f60807bd 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -33,9 +33,7 @@ import ( var ( sameDBname = true inDataDB migrator.MigratorDataDB - oldstorDB engine.Storage - oStorDBType string - oDataDBType string + instorDB engine.Storage oDBDataEncoding string migrate = flag.String("migrate", "", "Fire up automatic migration *to use multiple values use ',' as separator \n <*set_versions|*cost_details|*accounts|*actions|*action_triggers|*action_plans|*shared_groups> ") version = flag.Bool("version", false, "Prints the application version.") @@ -47,12 +45,12 @@ var ( outDataDBUser = flag.String("out_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") outDataDBPass = flag.String("out_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") - storDBType = flag.String("stordb_type", config.CgrConfig().StorDBType, "The type of the storDb Database ") - storDBHost = flag.String("stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") - storDBPort = flag.String("stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") - storDBName = flag.String("stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") - storDBUser = flag.String("stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") - storDBPass = flag.String("stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") + outStorDBType = flag.String("out_stordb_type", config.CgrConfig().StorDBType, "The type of the storDb Database ") + outStorDBHost = flag.String("out_stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") + outStorDBPort = flag.String("out_stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") + outStorDBName = flag.String("out_stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") + outStorDBUser = flag.String("out_stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") + outStorDBPass = flag.String("out_stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") inDataDBType = flag.String("in_datadb_type", "", "The type of the DataDb Database ") inDataDBHost = flag.String("in_datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") @@ -61,15 +59,15 @@ var ( inDataDBUser = flag.String("in_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") inDataDBPass = flag.String("in_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") - oldStorDBType = flag.String("old_stordb_type", "", "The type of the storDb Database ") - oldStorDBHost = flag.String("old_stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") - oldStorDBPort = flag.String("old_stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") - oldStorDBName = flag.String("old_stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") - oldStorDBUser = flag.String("old_stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") - oldStorDBPass = flag.String("old_stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") + inStorDBType = flag.String("in_stordb_type", "", "The type of the storDb Database ") + inStorDBHost = flag.String("in_stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") + inStorDBPort = flag.String("in_stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") + inStorDBName = flag.String("in_stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") + inStorDBUser = flag.String("in_stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") + inStorDBPass = flag.String("in_stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") - loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") - oldLoadHistorySize = flag.Int("old_load_history_size", 0, "Limit the number of records in the load history") + loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") + inLoadHistorySize = flag.Int("in_load_history_size", 0, "Limit the number of records in the load history") dbDataEncoding = flag.String("dbData_encoding", config.CgrConfig().DBDataEncoding, "The encoding used to store object Data in strings") inDBDataEncoding = flag.String("in_dbData_encoding", "", "The encoding used to store object Data in strings") @@ -87,11 +85,11 @@ func main() { if migrate != nil && *migrate != "" { // Run migrator if *verbose { log.Print("Initializing DataDB:", *outDataDBType) - log.Print("Initializing storDB:", *storDBType) + log.Print("Initializing storDB:", *outStorDBType) } var dmOUT *engine.DataManager dmOUT, _ = engine.ConfigureDataStorage(*outDataDBType, *outDataDBHost, *outDataDBPort, *outDataDBName, *outDataDBUser, *outDataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) - storDB, err := engine.ConfigureStorStorage(*storDBType, *storDBHost, *storDBPort, *storDBName, *storDBUser, *storDBPass, *dbDataEncoding, + storDB, err := engine.ConfigureStorStorage(*outStorDBType, *outStorDBHost, *outStorDBPort, *outStorDBName, *outStorDBUser, *outStorDBPass, *dbDataEncoding, config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) @@ -113,17 +111,17 @@ func main() { if err != nil { log.Fatal(err) } - oldstorDB = storDB + instorDB = storDB if *verbose { - if *oldStorDBType != "" { - log.Print("Initializing oldstorDB:", *oldStorDBType) + if *inStorDBType != "" { + log.Print("Initializing instorDB:", *inStorDBType) } else { - log.Print("Initializing oldstorDB:", *storDBType) + log.Print("Initializing instorDB:", *outStorDBType) } } - if *oldStorDBType != "" { - oldstorDB, err = engine.ConfigureStorStorage(oStorDBType, *oldStorDBHost, *oldStorDBPort, *oldStorDBName, *oldStorDBUser, *oldStorDBPass, *inDBDataEncoding, + if *inStorDBType != "" { + instorDB, err = engine.ConfigureStorStorage(*inStorDBType, *inStorDBHost, *inStorDBPort, *inStorDBName, *inStorDBUser, *inStorDBPass, *inDBDataEncoding, config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) @@ -135,7 +133,7 @@ func main() { if inDataDBName != outDataDBName { sameDBname = false } - m, err := migrator.NewMigrator(dmIN, dmOUT, *outDataDBType, *dbDataEncoding, storDB, *storDBType, inDataDB, *inDataDBType, *inDBDataEncoding, oldstorDB, *oldStorDBType, *dryRun, sameDBname) + m, err := migrator.NewMigrator(dmIN, dmOUT, *outDataDBType, *dbDataEncoding, storDB, *inStorDBType, inDataDB, *inDataDBType, *inDBDataEncoding, instorDB, *inStorDBType, *dryRun, sameDBname) if err != nil { log.Fatal(err) } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 796e68e78..b9cbb8c61 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -28,47 +28,35 @@ import ( "time" ) -func (ms *MongoStorage) GetTpIds(x string) ([]string, error) { +func (ms *MongoStorage) GetTpIds(colname string) ([]string, error) { tpidMap := make(map[string]bool) session := ms.session.Copy() db := session.DB(ms.db) defer session.Close() var tpids []string - if x != "" { - if strings.HasPrefix(x, "tp_") { + var err error + cols := []string{colname} + if colname == "" { + cols, err = db.CollectionNames() + if err != nil { + return nil, err + } + } + for _, col := range cols { + if strings.HasPrefix(col, "tp_") { tpids := make([]string, 0) - if err := db.C(x).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { + if err := db.C(col).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { return nil, err } for _, tpid := range tpids { tpidMap[tpid] = true } } - for tpid := range tpidMap { - tpids = append(tpids, tpid) - } - } else { - cols, err := db.CollectionNames() - if err != nil { - return nil, err - } - for _, col := range cols { - if strings.HasPrefix(col, "tp_") { - tpids := make([]string, 0) - if err := db.C(col).Find(nil).Select(bson.M{"tpid": 1}).Distinct("tpid", &tpids); err != nil { - return nil, err - } - for _, tpid := range tpids { - tpidMap[tpid] = true - } - } - } - for tpid := range tpidMap { - tpids = append(tpids, tpid) - } + } + for tpid := range tpidMap { + tpids = append(tpids, tpid) } return tpids, nil - } func (ms *MongoStorage) GetTpTableIds(tpid, table string, distinct utils.TPDistinctIds, filter map[string]string, pag *utils.Paginator) ([]string, error) { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 351400690..e1f643b1e 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -120,31 +120,18 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { // update // Return a list with all TPids defined in the system, even if incomplete, isolated in some table. -func (self *SQLStorage) GetTpIds(x string) ([]string, error) { - if x != "" { - rows, err := self.Db.Query( - fmt.Sprintf(" (SELECT tpid FROM %s)", x)) +func (self *SQLStorage) GetTpIds(colname string) ([]string, error) { + var rows *sql.Rows + var err error + if colname != "" { + rows, err = self.Db.Query( + fmt.Sprintf(" (SELECT tpid FROM %s)", colname)) if err != nil { return nil, err } defer rows.Close() - ids := make([]string, 0) - i := 0 - for rows.Next() { - i++ //Keep here a reference so we know we got at least one - var id string - err = rows.Scan(&id) - if err != nil { - return nil, err - } - ids = append(ids, id) - } - if i == 0 { - return nil, nil - } - return ids, nil } else { - rows, err := self.Db.Query( + rows, err = self.Db.Query( fmt.Sprintf( "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", utils.TBLTPTimings, @@ -171,23 +158,22 @@ func (self *SQLStorage) GetTpIds(x string) ([]string, error) { return nil, err } defer rows.Close() - ids := make([]string, 0) - i := 0 - for rows.Next() { - i++ //Keep here a reference so we know we got at least one - var id string - err = rows.Scan(&id) - if err != nil { - return nil, err - } - ids = append(ids, id) - } - if i == 0 { - return nil, nil - } - - return ids, nil } + ids := make([]string, 0) + i := 0 + for rows.Next() { + i++ //Keep here a reference so we know we got at least one + var id string + err = rows.Scan(&id) + if err != nil { + return nil, err + } + ids = append(ids, id) + } + if i == 0 { + return nil, nil + } + return ids, nil } // ToDo: TEST From 8913e8e6e99c24a6db9ba7c6bda3e7a6ddd3db7b Mon Sep 17 00:00:00 2001 From: DanB Date: Wed, 15 Nov 2017 15:03:05 +0100 Subject: [PATCH 49/75] Small formatting --- agents/dmtagent.go | 3 ++- agents/libdmt.go | 3 ++- agents/libdmt_test.go | 46 +++++++++++++++++++++++++++++++------------ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index d6b714a9c..40f224c0e 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -35,7 +35,8 @@ import ( "github.com/fiorix/go-diameter/diam/sm" ) -func NewDiameterAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection, pubsubs rpcclient.RpcClientConnection) (*DiameterAgent, error) { +func NewDiameterAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection, + pubsubs rpcclient.RpcClientConnection) (*DiameterAgent, error) { da := &DiameterAgent{cgrCfg: cgrCfg, smg: smg, pubsubs: pubsubs, connMux: new(sync.Mutex)} if reflect.ValueOf(da.pubsubs).IsNil() { da.pubsubs = nil // Empty it so we can check it later diff --git a/agents/libdmt.go b/agents/libdmt.go index 887ef5651..2273e6076 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -429,7 +429,8 @@ func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, // messageAddAVPsWithPath will dynamically add AVPs into the message // append: append to the message, on false overwrite if AVP is single or add to group if AVP is Grouped -func messageSetAVPsWithPath(m *diam.Message, path []interface{}, avpValStr string, appnd bool, timezone string) error { +func messageSetAVPsWithPath(m *diam.Message, path []interface{}, + avpValStr string, appnd bool, timezone string) error { if len(path) == 0 { return errors.New("Empty path as AVP filter") } diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index 5189ff549..eb42abf45 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -243,31 +243,46 @@ func TestSerializeAVPValueFromString(t *testing.T) { func TestMessageSetAVPsWithPath(t *testing.T) { eMessage := diam.NewRequest(diam.CreditControl, 4, nil) - eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) - m := diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) - if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id", "Unknown"}, "simuhuawei;1449573472;00002", false, "UTC"); err == nil || err.Error() != "Could not find AVP Unknown" { + eMessage.NewAVP("Session-Id", avp.Mbit, 0, + datatype.UTF8String("simuhuawei;1449573472;00002")) + m := diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, + eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) + if err := messageSetAVPsWithPath(m, + []interface{}{"Session-Id", "Unknown"}, "simuhuawei;1449573472;00002", + false, "UTC"); err == nil || + err.Error() != "Could not find AVP Unknown" { t.Error(err) } - if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, "simuhuawei;1449573472;00002", false, "UTC"); err != nil { + if err := messageSetAVPsWithPath(m, + []interface{}{"Session-Id"}, "simuhuawei;1449573472;00002", + false, "UTC"); err != nil { t.Error(err) } else if !reflect.DeepEqual(eMessage, m) { t.Errorf("Expecting: %+v, received: %+v", eMessage, m) } // test append - eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00003")) - if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, "simuhuawei;1449573472;00003", true, "UTC"); err != nil { + eMessage.NewAVP("Session-Id", avp.Mbit, 0, + datatype.UTF8String("simuhuawei;1449573472;00003")) + if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, + "simuhuawei;1449573472;00003", true, "UTC"); err != nil { t.Error(err) } else if !reflect.DeepEqual(eMessage, m) { t.Errorf("Expecting: %+v, received: %+v", eMessage, m) } // test overwrite eMessage = diam.NewRequest(diam.CreditControl, 4, nil) - eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) - m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) - if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, "simuhuawei;1449573472;00001", false, "UTC"); err != nil { + eMessage.NewAVP("Session-Id", avp.Mbit, 0, + datatype.UTF8String("simuhuawei;1449573472;00002")) + m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, + eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) + if err := messageSetAVPsWithPath(m, + []interface{}{"Session-Id"}, "simuhuawei;1449573472;00001", + false, "UTC"); err != nil { t.Error(err) } - if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, "simuhuawei;1449573472;00002", false, "UTC"); err != nil { + if err := messageSetAVPsWithPath(m, + []interface{}{"Session-Id"}, "simuhuawei;1449573472;00002", + false, "UTC"); err != nil { t.Error(err) } else if !reflect.DeepEqual(eMessage, m) { t.Errorf("Expecting: %+v, received: %+v", eMessage, m) @@ -277,8 +292,11 @@ func TestMessageSetAVPsWithPath(t *testing.T) { AVP: []*diam.AVP{ diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data }}) - m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) - if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Data"}, "33708000003", false, "UTC"); err != nil { + m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, + eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil) + if err := messageSetAVPsWithPath(m, + []interface{}{"Subscription-Id", "Subscription-Id-Data"}, + "33708000003", false, "UTC"); err != nil { t.Error(err) } else if !reflect.DeepEqual(eMessage, m) { t.Errorf("Expecting: %+v, received: %+v", eMessage, m) @@ -288,7 +306,9 @@ func TestMessageSetAVPsWithPath(t *testing.T) { AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Data }}) - if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Type"}, "0", true, "UTC"); err != nil { + if err := messageSetAVPsWithPath(m, + []interface{}{"Subscription-Id", "Subscription-Id-Type"}, + "0", true, "UTC"); err != nil { t.Error(err) } else if !reflect.DeepEqual(eMessage, m) { t.Errorf("Expecting: %+v, received: %+v", eMessage, m) From a028c64922422b13b4e3c7ac40eddb6868632261 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 14 Nov 2017 10:26:07 +0200 Subject: [PATCH 50/75] Add test for FilterToTPFilter --- engine/model_helpers_test.go | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index aa21f8797..db2709966 100755 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -21,6 +21,7 @@ package engine import ( "reflect" "testing" + "time" "github.com/cgrates/cgrates/utils" ) @@ -1021,3 +1022,40 @@ func TestAPItoTPFilter(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eTPs, st) } } + +func TestFilterToTPFilter(t *testing.T) { + filter := &Filter{ + Tenant: "cgrates.org", + ID: "Fltr1", + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 1, 14, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2014, 1, 14, 0, 0, 0, 0, time.UTC), + }, + RequestFilters: []*RequestFilter{ + &RequestFilter{ + FieldName: "Account", + Type: "*string", + Values: []string{"1001", "1002"}, + }, + }, + } + tpfilter := &utils.TPFilter{ + ID: "Fltr1", + Tenant: "cgrates.org", + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-01-14T00:00:00Z", + ExpiryTime: "2014-01-14T00:00:00Z", + }, + Filters: []*utils.TPRequestFilter{ + &utils.TPRequestFilter{ + FieldName: "Account", + Type: "*string", + Values: []string{"1001", "1002"}, + }, + }, + } + eTPFilter := FilterToTPFilter(filter) + if !reflect.DeepEqual(tpfilter, eTPFilter) { + t.Errorf("Expecting: %+v, received: %+v", tpfilter, eTPFilter) + } +} From ebc7a9eb0213996b1911aac6873e96b6c4f5c4e2 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 14 Nov 2017 10:56:31 +0200 Subject: [PATCH 51/75] Add confil filters tests --- config/config_json_test.go | 11 +++++++++++ config/config_test.go | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/config/config_json_test.go b/config/config_json_test.go index 7ec072018..e97754ea0 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -691,6 +691,17 @@ func TestDfUserServJsonCfg(t *testing.T) { } } +func TestDfFilterSJsonCfg(t *testing.T) { + eCfg := &FilterSJsonCfg{ + Stats_conns: &[]*HaPoolJsonCfg{}, + } + if cfg, err := dfCgrJsonCfg.FilterSJsonCfg(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eCfg, cfg) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(eCfg), utils.ToJSON(cfg)) + } +} + func TestDfResourceLimiterSJsonCfg(t *testing.T) { eCfg := &ResourceSJsonCfg{ Enabled: utils.BoolPointer(false), diff --git a/config/config_test.go b/config/config_test.go index 6f6264d26..60fa69c93 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -287,7 +287,7 @@ func TestCgrCfgJSONDefaultsStorDB(t *testing.T) { } func TestCgrCfgJSONDefaultsRALs(t *testing.T) { - + //asd eHaPoolcfg := []*HaPoolConfig{} if cgrCfg.RALsEnabled != false { @@ -624,6 +624,15 @@ func TestCgrCfgJSONDefaultsUserS(t *testing.T) { } } +func TestCgrCfgJSONDefaultFiltersCfg(t *testing.T) { + eFiltersCfg := &FilterSCfg{ + StatSConns: []*HaPoolConfig{}, + } + if !reflect.DeepEqual(cgrCfg.filterSCfg, eFiltersCfg) { + t.Errorf("received: %+v, expecting: %+v", cgrCfg.filterSCfg, eFiltersCfg) + } +} + func TestCgrCfgJSONDefaultsResLimCfg(t *testing.T) { eResLiCfg := &ResourceSConfig{ Enabled: false, From 332c489d0f25b4be588598e5863a8a6cd9111a30 Mon Sep 17 00:00:00 2001 From: TeoV Date: Tue, 14 Nov 2017 12:46:02 +0200 Subject: [PATCH 52/75] AsStoredCdr -> AsCDR --- apier/v1/auth.go | 2 +- cmd/cgr-migrator/cgr-migrator.go | 4 ++-- engine/cdr.go | 4 ++-- engine/cdr_test.go | 2 +- engine/cdrs.go | 4 ++-- engine/cgrcdr.go | 2 +- engine/cgrcdr_test.go | 4 ++-- engine/event.go | 2 +- engine/fscdr.go | 2 +- engine/fscdr_test.go | 2 +- engine/rawcdr.go | 2 +- engine/storage_sql.go | 2 +- general_tests/fsevcorelate_test.go | 16 ++++++++-------- sessionmanager/fsevent.go | 2 +- sessionmanager/fsevent_test.go | 4 ++-- sessionmanager/fssessionmanager.go | 4 ++-- sessionmanager/kamailiosm.go | 4 ++-- sessionmanager/kamevent.go | 2 +- sessionmanager/osipsevent.go | 2 +- sessionmanager/osipsevent_test.go | 6 +++--- sessionmanager/osipssm.go | 4 ++-- sessionmanager/session.go | 2 +- sessionmanager/smg_event.go | 2 +- sessionmanager/smg_event_test.go | 4 ++-- sessionmanager/smgeneric.go | 11 +++++------ 25 files changed, 47 insertions(+), 48 deletions(-) diff --git a/apier/v1/auth.go b/apier/v1/auth.go index 28b6b4945..80a3556f4 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -53,7 +53,7 @@ func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float if usageRecord.Usage == "" { usageRecord.Usage = strconv.FormatFloat(self.Config.MaxCallDuration.Seconds(), 'f', -1, 64) } - storedCdr, err := usageRecord.AsStoredCdr(self.Config.DefaultTimezone) + storedCdr, err := usageRecord.AsCDR(self.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index 5f60807bd..b97af5166 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -88,7 +88,7 @@ func main() { log.Print("Initializing storDB:", *outStorDBType) } var dmOUT *engine.DataManager - dmOUT, _ = engine.ConfigureDataStorage(*outDataDBType, *outDataDBHost, *outDataDBPort, *outDataDBName, *outDataDBUser, *outDataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) + dmOUT, _ = engine.ConfigureDataStorage(*outDataDBType, *outDataDBHost, *outDataDBPort, *outDataDBName, *outDataDBUser, *outDataDBPass, *dbDataEncoding, config.CgrConfig().CacheCfg(), *loadHistorySize) storDB, err := engine.ConfigureStorStorage(*outStorDBType, *outStorDBHost, *outStorDBPort, *outStorDBName, *outStorDBUser, *outStorDBPass, *dbDataEncoding, config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { @@ -106,7 +106,7 @@ func main() { log.Print("Initializing inDataDB:", *inDataDBType) } var dmIN *engine.DataManager - dmIN, _ = engine.ConfigureDataStorage(*inDataDBType, *inDataDBHost, *inDataDBPort, *inDataDBName, *inDataDBUser, *inDataDBPass, *dbDataEncoding, config.CgrConfig().CacheConfig, *loadHistorySize) + dmIN, _ = engine.ConfigureDataStorage(*inDataDBType, *inDataDBHost, *inDataDBPort, *inDataDBName, *inDataDBUser, *inDataDBPass, *dbDataEncoding, config.CgrConfig().CacheCfg(), *loadHistorySize) inDataDB, err := migrator.ConfigureV1DataStorage(*inDataDBType, *inDataDBHost, *inDataDBPort, *inDataDBName, *inDataDBUser, *inDataDBPass, *dbDataEncoding) if err != nil { log.Fatal(err) diff --git a/engine/cdr.go b/engine/cdr.go index 792f97f24..6c33eef33 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -252,7 +252,7 @@ func (cdr *CDR) FieldsAsString(rsrFlds utils.RSRFields) string { return fldVal } -func (cdr *CDR) AsStoredCdr(timezone string) *CDR { +func (cdr *CDR) AsCDR(timezone string) *CDR { return cdr } @@ -867,7 +867,7 @@ type UsageRecord struct { ExtraFields map[string]string } -func (self *UsageRecord) AsStoredCdr(timezone string) (*CDR, error) { +func (self *UsageRecord) AsCDR(timezone string) (*CDR, error) { var err error cdr := &CDR{CGRID: self.GetId(), ToR: self.ToR, RequestType: self.RequestType, Tenant: self.Tenant, Category: self.Category, Account: self.Account, Subject: self.Subject, Destination: self.Destination} diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 48ae792e9..94a4b2451 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -485,7 +485,7 @@ func TesUsageReqAsCDR(t *testing.T) { SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10)} - if CDR, err := setupReq.AsStoredCdr(""); err != nil { + if CDR, err := setupReq.AsCDR(""); err != nil { t.Error(err) } else if !reflect.DeepEqual(eStorCdr, CDR) { t.Errorf("Expected: %+v, received: %+v", eStorCdr, CDR) diff --git a/engine/cdrs.go b/engine/cdrs.go index b116399c8..33c2189c6 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -51,7 +51,7 @@ func cgrCdrHandler(w http.ResponseWriter, r *http.Request) { utils.Logger.Err(fmt.Sprintf(" Could not create CDR entry: %s", err.Error())) return } - if err := cdrServer.processCdr(cgrCdr.AsStoredCdr(cdrServer.cgrCfg.DefaultTimezone)); err != nil { + if err := cdrServer.processCdr(cgrCdr.AsCDR(cdrServer.cgrCfg.DefaultTimezone)); err != nil { utils.Logger.Err(fmt.Sprintf(" Errors when storing CDR entry: %s", err.Error())) } } @@ -64,7 +64,7 @@ func fsCdrHandler(w http.ResponseWriter, r *http.Request) { utils.Logger.Err(fmt.Sprintf(" Could not create CDR entry: %s", err.Error())) return } - if err := cdrServer.processCdr(fsCdr.AsStoredCdr(cdrServer.Timezone())); err != nil { + if err := cdrServer.processCdr(fsCdr.AsCDR(cdrServer.Timezone())); err != nil { utils.Logger.Err(fmt.Sprintf(" Errors when storing CDR entry: %s", err.Error())) } } diff --git a/engine/cgrcdr.go b/engine/cgrcdr.go index 578a20a54..e59b9df49 100644 --- a/engine/cgrcdr.go +++ b/engine/cgrcdr.go @@ -58,7 +58,7 @@ func (cgrCdr CgrCdr) getExtraFields() map[string]string { return extraFields } -func (cgrCdr CgrCdr) AsStoredCdr(timezone string) *CDR { +func (cgrCdr CgrCdr) AsCDR(timezone string) *CDR { storCdr := new(CDR) storCdr.CGRID = cgrCdr.getCGRID(timezone) storCdr.ToR = cgrCdr[utils.TOR] diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index 8a7b8d963..71ad57a00 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -52,7 +52,7 @@ func TestCgrCdrAsCDR(t *testing.T) { AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, Cost: -1, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} - if CDR := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, CDR) { + if CDR := cgrCdr.AsCDR(""); !reflect.DeepEqual(expctRtCdr, CDR) { t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR) } } @@ -81,7 +81,7 @@ func TestReplicatedCgrCdrAsCDR(t *testing.T) { ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 0.12, Rated: true, } - if CDR := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, CDR) { + if CDR := cgrCdr.AsCDR(""); !reflect.DeepEqual(expctRtCdr, CDR) { t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR) } } diff --git a/engine/event.go b/engine/event.go index 3f1af1eea..bc0a7855e 100644 --- a/engine/event.go +++ b/engine/event.go @@ -43,7 +43,7 @@ type Event interface { GetExtraFields() map[string]string MissingParameter(string) bool ParseEventValue(*utils.RSRField, string) string - AsStoredCdr(timezone string) *CDR + AsCDR(timezone string) *CDR String() string AsEvent(string) Event ComputeLcr() bool diff --git a/engine/fscdr.go b/engine/fscdr.go index 5f42497a0..66d9bb1cc 100644 --- a/engine/fscdr.go +++ b/engine/fscdr.go @@ -122,7 +122,7 @@ func (fsCdr FSCdr) searchExtraField(field string, body map[string]interface{}) ( return } -func (fsCdr FSCdr) AsStoredCdr(timezone string) *CDR { +func (fsCdr FSCdr) AsCDR(timezone string) *CDR { storCdr := new(CDR) storCdr.CGRID = fsCdr.getCGRID(timezone) storCdr.ToR = utils.VOICE diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go index 37dce794b..568eb2824 100644 --- a/engine/fscdr_test.go +++ b/engine/fscdr_test.go @@ -62,7 +62,7 @@ func TestCDRFields(t *testing.T) { AnswerTime: answerTime, Usage: time.Duration(66) * time.Second, Cost: -1, ExtraFields: map[string]string{"sip_user_agent": "PJSUA v2.3 Linux-3.2.0.4/x86_64/glibc-2.13"}} - if CDR := fsCdr.AsStoredCdr(""); !reflect.DeepEqual(expctCDR, CDR) { + if CDR := fsCdr.AsCDR(""); !reflect.DeepEqual(expctCDR, CDR) { t.Errorf("Expecting: %v, received: %v", expctCDR, CDR) } } diff --git a/engine/rawcdr.go b/engine/rawcdr.go index cbb3f1d68..e72d4e676 100644 --- a/engine/rawcdr.go +++ b/engine/rawcdr.go @@ -20,5 +20,5 @@ package engine // RawCDR is the original CDR received from external sources (eg: FreeSWITCH) type RawCdr interface { - AsStoredCdr(string) *CDR // Convert the inbound Cdr into internally used one, CgrCdr + AsCDR(string) *CDR // Convert the inbound Cdr into internally used one, CgrCdr } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index e1f643b1e..e9a5cb8a0 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -107,7 +107,7 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, utils.TBLTPDerivedChargers, utils.TBLTPUsers, utils.TBLTPAliases, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPThresholds, - utils.TBLTPFilters, utils.TBLSMCosts, utils.TBLCDRs, utils.TBLTPActionPlans, utils.TBLVersions, + utils.TBLTPFilters, utils.SMCostsTBL, utils.CDRsTBL, utils.TBLTPActionPlans, utils.TBLVersions, } for _, tbl := range tbls { if self.db.HasTable(tbl) { diff --git a/general_tests/fsevcorelate_test.go b/general_tests/fsevcorelate_test.go index d7e06ac36..fd125ddad 100644 --- a/general_tests/fsevcorelate_test.go +++ b/general_tests/fsevcorelate_test.go @@ -221,11 +221,11 @@ func TestEvCorelate(t *testing.T) { cdrEv, err := engine.NewFSCdr(jsonCdr, cfg) if err != nil { t.Errorf("Error loading cdr: %v", err.Error()) - } else if cdrEv.AsStoredCdr("").OriginID != "86cfd6e2-dbda-45a3-b59d-f683ec368e8b" { - t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").OriginID) + } else if cdrEv.AsCDR("").OriginID != "86cfd6e2-dbda-45a3-b59d-f683ec368e8b" { + t.Error("Unexpected acntId received", cdrEv.AsCDR("").OriginID) } - if answerEv.GetCgrId("") != cdrEv.AsStoredCdr("").CGRID { - t.Error("CGRIDs do not match", answerEv.GetCgrId(""), cdrEv.AsStoredCdr("").CGRID) + if answerEv.GetCgrId("") != cdrEv.AsCDR("").CGRID { + t.Error("CGRIDs do not match", answerEv.GetCgrId(""), cdrEv.AsCDR("").CGRID) } } @@ -549,14 +549,14 @@ func TestEvCdrCorelate(t *testing.T) { } cfg, _ := config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) - evStoredCdr := hangupEv.AsStoredCdr("") + evStoredCdr := hangupEv.AsCDR("") cdrEv, err := engine.NewFSCdr(jsonCdr2, cfg) if err != nil { t.Errorf("Error loading cdr: %v", err.Error()) - } else if cdrEv.AsStoredCdr("").OriginID != "e3133bf7-dcde-4daf-9663-9a79ffcef5ad" { - t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").OriginID) + } else if cdrEv.AsCDR("").OriginID != "e3133bf7-dcde-4daf-9663-9a79ffcef5ad" { + t.Error("Unexpected acntId received", cdrEv.AsCDR("").OriginID) } - jsnStoredCdr := cdrEv.AsStoredCdr("") + jsnStoredCdr := cdrEv.AsCDR("") if evStoredCdr.CGRID != jsnStoredCdr.CGRID { t.Errorf("evStoredCdr.CGRID: %s, jsnStoredCdr.CGRID: %s", evStoredCdr.CGRID, jsnStoredCdr.CGRID) } diff --git a/sessionmanager/fsevent.go b/sessionmanager/fsevent.go index 5a546060f..dfdca569f 100644 --- a/sessionmanager/fsevent.go +++ b/sessionmanager/fsevent.go @@ -339,7 +339,7 @@ func (fsev FSEvent) PassesFieldFilter(fieldFilter *utils.RSRField) (bool, string } */ -func (fsev FSEvent) AsStoredCdr(timezone string) *engine.CDR { +func (fsev FSEvent) AsCDR(timezone string) *engine.CDR { storCdr := new(engine.CDR) storCdr.CGRID = fsev.GetCgrId(timezone) storCdr.ToR = utils.VOICE diff --git a/sessionmanager/fsevent_test.go b/sessionmanager/fsevent_test.go index 3c68a7f41..3dbdc4acf 100644 --- a/sessionmanager/fsevent_test.go +++ b/sessionmanager/fsevent_test.go @@ -610,7 +610,7 @@ Caller-Username: 04021292812` } */ -func TestFsEvAsStoredCdr(t *testing.T) { +func TestFsEvAsCDR(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) ev := new(FSEvent).AsEvent(hangupEv) @@ -623,7 +623,7 @@ func TestFsEvAsStoredCdr(t *testing.T) { Destination: "1003", SetupTime: setupTime, AnswerTime: aTime, Usage: time.Duration(66) * time.Second, ExtraFields: make(map[string]string), Cost: -1} - if storedCdr := ev.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { + if storedCdr := ev.AsCDR(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } } diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index c378672ee..246095e2e 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -163,7 +163,7 @@ func (sm *FSSessionManager) onChannelPark(ev engine.Event, connId string) { if ev.GetReqType(utils.META_DEFAULT) != utils.META_NONE { // Do not process this request var maxCallDuration float64 // This will be the maximum duration this channel will be allowed to last if err := sm.rater.Call("Responder.GetDerivedMaxSessionTime", - ev.AsStoredCdr(config.CgrConfig().DefaultTimezone), &maxCallDuration); err != nil { + ev.AsCDR(config.CgrConfig().DefaultTimezone), &maxCallDuration); err != nil { utils.Logger.Err(fmt.Sprintf(" Could not get max session time for %s, error: %s", ev.GetUUID(), err.Error())) } @@ -276,7 +276,7 @@ func (sm *FSSessionManager) onChannelHangupComplete(ev engine.Event) { } } if sm.cfg.CreateCdr { - sm.ProcessCdr(ev.AsStoredCdr(config.CgrConfig().DefaultTimezone)) + sm.ProcessCdr(ev.AsCDR(config.CgrConfig().DefaultTimezone)) } var reply string attrRU := utils.ArgRSv1ResourceUsage{ diff --git a/sessionmanager/kamailiosm.go b/sessionmanager/kamailiosm.go index 7ffdfd67f..83147ac88 100644 --- a/sessionmanager/kamailiosm.go +++ b/sessionmanager/kamailiosm.go @@ -110,7 +110,7 @@ func (self *KamailioSessionManager) onCgrAuth(evData []byte, connId string) { var remainingDuration float64 var errReply error if errReply = self.rater.Call("Responder.GetDerivedMaxSessionTime", - kev.AsStoredCdr(self.timezone), &remainingDuration); errReply != nil { + kev.AsCDR(self.timezone), &remainingDuration); errReply != nil { utils.Logger.Err(fmt.Sprintf(" Could not get max session time, error: %s", errReply.Error())) } var supplStr string @@ -205,7 +205,7 @@ func (self *KamailioSessionManager) onCallEnd(evData []byte, connId string) { if kev.MissingParameter(self.timezone) { utils.Logger.Err(fmt.Sprintf(" Mandatory IE missing out of event: %+v", kev)) } - go self.ProcessCdr(kev.AsStoredCdr(self.Timezone())) + go self.ProcessCdr(kev.AsCDR(self.Timezone())) if self.rlS != nil { // Release RLs resource go func() { ev, err := kev.AsMapStringIface() diff --git a/sessionmanager/kamevent.go b/sessionmanager/kamevent.go index e2077eddc..6f9a40a5a 100644 --- a/sessionmanager/kamevent.go +++ b/sessionmanager/kamevent.go @@ -320,7 +320,7 @@ func (kev KamEvent) PassesFieldFilter(*utils.RSRField) (bool, string) { return false, "" } -func (kev KamEvent) AsStoredCdr(timezone string) *engine.CDR { +func (kev KamEvent) AsCDR(timezone string) *engine.CDR { storCdr := new(engine.CDR) storCdr.CGRID = kev.GetCgrId(timezone) storCdr.ToR = utils.VOICE diff --git a/sessionmanager/osipsevent.go b/sessionmanager/osipsevent.go index 2fb3f3ce3..d246d2ee3 100644 --- a/sessionmanager/osipsevent.go +++ b/sessionmanager/osipsevent.go @@ -264,7 +264,7 @@ func (osipsev *OsipsEvent) DialogId() string { return osipsev.osipsEvent.AttrValues[OSIPS_DIALOG_ID] } -func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.CDR { +func (osipsEv *OsipsEvent) AsCDR(timezone string) *engine.CDR { storCdr := new(engine.CDR) storCdr.CGRID = osipsEv.GetCgrId(timezone) storCdr.ToR = utils.VOICE diff --git a/sessionmanager/osipsevent_test.go b/sessionmanager/osipsevent_test.go index 102b2dab7..35964e5a7 100644 --- a/sessionmanager/osipsevent_test.go +++ b/sessionmanager/osipsevent_test.go @@ -139,7 +139,7 @@ func TestOsipsEventMissingParameter(t *testing.T) { } } -func TestOsipsEventAsStoredCdr(t *testing.T) { +func TestOsipsEventAsCDR(t *testing.T) { setupTime, _ := utils.ParseTimeDetectLayout("1406370492", "") answerTime, _ := utils.ParseTimeDetectLayout("1406370499", "") eStoredCdr := &engine.CDR{ @@ -151,7 +151,7 @@ func TestOsipsEventAsStoredCdr(t *testing.T) { Destination: "+4986517174963", SetupTime: setupTime, AnswerTime: answerTime, Usage: time.Duration(20) * time.Second, ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} - if storedCdr := osipsEv.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { + if storedCdr := osipsEv.AsCDR(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } } @@ -169,7 +169,7 @@ func TestOsipsAccMissedToStoredCdr(t *testing.T) { RequestType: utils.META_PSEUDOPREPAID, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: setupTime, AnswerTime: setupTime, Usage: time.Duration(0), ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} - if storedCdr := osipsEv.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { + if storedCdr := osipsEv.AsCDR(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } diff --git a/sessionmanager/osipssm.go b/sessionmanager/osipssm.go index f6965c7dd..b82213ee4 100644 --- a/sessionmanager/osipssm.go +++ b/sessionmanager/osipssm.go @@ -232,7 +232,7 @@ func (osm *OsipsSessionManager) onOpensipsStart(cdrDagram *osipsdagram.OsipsEven // Triggered by CDR event func (osm *OsipsSessionManager) onCdr(cdrDagram *osipsdagram.OsipsEvent) { osipsEv, _ := NewOsipsEvent(cdrDagram) - if err := osm.ProcessCdr(osipsEv.AsStoredCdr(osm.timezone)); err != nil { + if err := osm.ProcessCdr(osipsEv.AsCDR(osm.timezone)); err != nil { utils.Logger.Err(fmt.Sprintf(" Failed processing CDR, cgrid: %s, accid: %s, error: <%s>", osipsEv.GetCgrId(osm.timezone), osipsEv.GetUUID(), err.Error())) } } @@ -334,7 +334,7 @@ func (osm *OsipsSessionManager) processCdrStop(osipsEv *OsipsEvent) error { if err := osipsEvStart.updateDurationFromEvent(osipsEv); err != nil { return err } - return osm.ProcessCdr(osipsEvStart.AsStoredCdr(osm.timezone)) + return osm.ProcessCdr(osipsEvStart.AsCDR(osm.timezone)) } func (osm *OsipsSessionManager) Sessions() []*Session { diff --git a/sessionmanager/session.go b/sessionmanager/session.go index f91f2923a..14cadcbde 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -59,7 +59,7 @@ func NewSession(ev engine.Event, connId string, sm SessionManager) *Session { sessionManager: sm, connId: connId, } - if err := sm.Rater().Call("Responder.GetSessionRuns", ev.AsStoredCdr(s.sessionManager.Timezone()), &s.sessionRuns); err != nil || len(s.sessionRuns) == 0 { + if err := sm.Rater().Call("Responder.GetSessionRuns", ev.AsCDR(s.sessionManager.Timezone()), &s.sessionRuns); err != nil || len(s.sessionRuns) == 0 { return nil } for runIdx := range s.sessionRuns { diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 60f2447a5..009928976 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -419,7 +419,7 @@ func (self SMGenericEvent) PassesFieldFilter(*utils.RSRField) (bool, string) { return true, "" } -func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) *engine.CDR { +func (self SMGenericEvent) AsCDR(cfg *config.CGRConfig, timezone string) *engine.CDR { storCdr := engine.NewCDRWithDefaults(cfg) storCdr.CGRID = self.GetCGRID(utils.META_DEFAULT) storCdr.ToR = utils.FirstNonEmpty(self.GetTOR(utils.META_DEFAULT), storCdr.ToR) // Keep default if none in the event diff --git a/sessionmanager/smg_event_test.go b/sessionmanager/smg_event_test.go index e95bdfbe1..b164922aa 100644 --- a/sessionmanager/smg_event_test.go +++ b/sessionmanager/smg_event_test.go @@ -150,7 +150,7 @@ func TestSMGenericEventGetSessionTTL(t *testing.T) { } } -func TestSMGenericEventAsStoredCdr(t *testing.T) { +func TestSMGenericEventAsCDR(t *testing.T) { smGev := SMGenericEvent{} smGev[utils.EVENT_NAME] = "TEST_EVENT" smGev[utils.TOR] = utils.SMS @@ -179,7 +179,7 @@ func TestSMGenericEventAsStoredCdr(t *testing.T) { AnswerTime: time.Date(2015, 11, 9, 14, 22, 2, 0, time.UTC), Usage: time.Duration(83) * time.Second, ExtraFields: map[string]string{"Extra1": "Value1", "Extra2": "5"}, Cost: -1} - if storedCdr := smGev.AsStoredCdr(cfg, "UTC"); !reflect.DeepEqual(eStoredCdr, storedCdr) { + if storedCdr := smGev.AsCDR(cfg, "UTC"); !reflect.DeepEqual(eStoredCdr, storedCdr) { t.Errorf("Expecting: %+v, received: %+v", eStoredCdr, storedCdr) } } diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 2a9e906d9..ca9375d44 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -185,7 +185,7 @@ func (smg *SMGeneric) ttlTerminate(s *SMGSession, tmtr *smgSessionTerminator) { s.debit(debitUsage, tmtr.ttlLastUsed) } smg.sessionEnd(s.CGRID, s.TotalUsage) - cdr := s.EventStart.AsStoredCdr(smg.cgrCfg, smg.Timezone) + cdr := s.EventStart.AsCDR(smg.cgrCfg, smg.Timezone) cdr.Usage = s.TotalUsage var reply string smg.cdrsrv.Call("CdrsV1.ProcessCDR", cdr, &reply) @@ -369,8 +369,7 @@ func (smg *SMGeneric) sessionStart(evStart SMGenericEvent, return nil, nil // ToDo: handle here also debits } var sessionRuns []*engine.SessionRun - if err := smg.rals.Call("Responder.GetSessionRuns", - evStart.AsStoredCdr(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { + if err := smg.rals.Call("Responder.GetSessionRuns", evStart.AsCDR(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { return nil, err } else if len(sessionRuns) == 0 { return nil, nil @@ -660,7 +659,7 @@ func (smg *SMGeneric) GetMaxUsage(gev SMGenericEvent) (maxUsage time.Duration, e } defer smg.responseCache.Cache(cacheKey, &cache.CacheItem{Value: maxUsage, Err: err}) gev[utils.EVENT_NAME] = utils.CGR_AUTHORIZATION - storedCdr := gev.AsStoredCdr(config.CgrConfig(), smg.Timezone) + storedCdr := gev.AsCDR(config.CgrConfig(), smg.Timezone) var maxDur float64 if err = smg.rals.Call("Responder.GetDerivedMaxSessionTime", storedCdr, &maxDur); err != nil { return @@ -865,7 +864,7 @@ func (smg *SMGeneric) ChargeEvent(gev SMGenericEvent) (maxUsage time.Duration, e } defer smg.responseCache.Cache(cacheKey, &cache.CacheItem{Value: maxUsage, Err: err}) var sessionRuns []*engine.SessionRun - if err = smg.rals.Call("Responder.GetSessionRuns", gev.AsStoredCdr(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { + if err = smg.rals.Call("Responder.GetSessionRuns", gev.AsCDR(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { return } else if len(sessionRuns) == 0 { return @@ -970,7 +969,7 @@ func (smg *SMGeneric) ProcessCDR(gev SMGenericEvent) (err error) { defer smg.responseCache.Cache(cacheKey, &cache.CacheItem{Err: err}) var reply string if err = smg.cdrsrv.Call("CdrsV1.ProcessCDR", - gev.AsStoredCdr(smg.cgrCfg, smg.Timezone), &reply); err != nil { + gev.AsCDR(smg.cgrCfg, smg.Timezone), &reply); err != nil { return } return From 2e6a0f4d014737691ecfc46596445124cae05be9 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 13:23:57 +0200 Subject: [PATCH 53/75] CDRExporter filename fixed (.csv and .fwv) --- apier/v1/cdre.go | 11 ++++++++++- apier/v2/cdre.go | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go index 177636164..aec771e74 100644 --- a/apier/v1/cdre.go +++ b/apier/v1/cdre.go @@ -267,7 +267,16 @@ func (self *ApierV1) ExportCDRs(arg ArgExportCDRs, reply *RplExportedCDRs) (err if arg.ExportID != nil && len(*arg.ExportID) != 0 { exportID = *arg.ExportID } - fileName := fmt.Sprintf("cdre_%s.%s", exportID, exportFormat) + var expFormat string + switch exportFormat { + case utils.MetaFileFWV: + expFormat = "fwv" + case utils.MetaFileCSV: + expFormat = "csv" + default: + expFormat = exportFormat + } + fileName := fmt.Sprintf("cdre_%s.%s", exportID, expFormat) if arg.ExportFileName != nil && len(*arg.ExportFileName) != 0 { fileName = *arg.ExportFileName } diff --git a/apier/v2/cdre.go b/apier/v2/cdre.go index 46ec12f13..068dd8e5b 100644 --- a/apier/v2/cdre.go +++ b/apier/v2/cdre.go @@ -89,7 +89,16 @@ func (self *ApierV2) ExportCdrsToFile(attr AttrExportCdrsToFile, reply *Exported if attr.ExportID != nil && len(*attr.ExportID) != 0 { exportID = *attr.ExportID } - fileName := fmt.Sprintf("cdre_%s.%s", exportID, exportFormat) + var expFormat string + switch exportFormat { + case utils.MetaFileFWV: + expFormat = "fwv" + case utils.MetaFileCSV: + expFormat = "csv" + default: + expFormat = exportFormat + } + fileName := fmt.Sprintf("cdre_%s.%s", exportID, expFormat) if attr.ExportFileName != nil && len(*attr.ExportFileName) != 0 { fileName = *attr.ExportFileName } From 3a93784fe8f8d24e984a44f252ef324504507101 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 13:42:29 +0200 Subject: [PATCH 54/75] Console cdr_exporter result updated --- console/cdrs_export.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/console/cdrs_export.go b/console/cdrs_export.go index 222013bfd..77d0c76fe 100644 --- a/console/cdrs_export.go +++ b/console/cdrs_export.go @@ -57,5 +57,6 @@ func (self *CmdExportCdrs) PostprocessRpcParams() error { } func (self *CmdExportCdrs) RpcResult() interface{} { - return new(v1.ArgExportCDRs) + var reply *v1.RplExportedCDRs + return &reply } From 9720b77e1ca98895791486a2964a7090d752dcfd Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 14:20:56 +0200 Subject: [PATCH 55/75] Add in console threshol threshold_set threshold_remove --- console/threshold.go | 66 +++++++++++++++++++++++++++++++++++++ console/threshold_remove.go | 63 +++++++++++++++++++++++++++++++++++ console/threshold_set.go | 63 +++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 console/threshold.go create mode 100644 console/threshold_remove.go create mode 100644 console/threshold_set.go diff --git a/console/threshold.go b/console/threshold.go new file mode 100644 index 000000000..fa9a4f927 --- /dev/null +++ b/console/threshold.go @@ -0,0 +1,66 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func init() { + c := &CmdGetThreshold{ + name: "threshold", + rpcMethod: "ApierV1.GetThresholdProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdGetThreshold struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdGetThreshold) Name() string { + return self.name +} + +func (self *CmdGetThreshold) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdGetThreshold) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdGetThreshold) PostprocessRpcParams() error { + return nil +} + +func (self *CmdGetThreshold) RpcResult() interface{} { + atr := engine.ThresholdProfile{} + return &atr +} diff --git a/console/threshold_remove.go b/console/threshold_remove.go new file mode 100644 index 000000000..876b74b16 --- /dev/null +++ b/console/threshold_remove.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/utils" + +func init() { + c := &CmdRemoveThreshold{ + name: "threshold_remove", + rpcMethod: "ApierV1.RemThresholdProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdRemoveThreshold struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdRemoveThreshold) Name() string { + return self.name +} + +func (self *CmdRemoveThreshold) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdRemoveThreshold) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdRemoveThreshold) PostprocessRpcParams() error { + return nil +} + +func (self *CmdRemoveThreshold) RpcResult() interface{} { + var s string + return &s +} diff --git a/console/threshold_set.go b/console/threshold_set.go new file mode 100644 index 000000000..2485f2668 --- /dev/null +++ b/console/threshold_set.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/engine" + +func init() { + c := &CmdSetThreshold{ + name: "threshold_set", + rpcMethod: "ApierV1.SetThresholdProfile", + rpcParams: &engine.ThresholdProfile{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdSetThreshold struct { + name string + rpcMethod string + rpcParams *engine.ThresholdProfile + *CommandExecuter +} + +func (self *CmdSetThreshold) Name() string { + return self.name +} + +func (self *CmdSetThreshold) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdSetThreshold) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &engine.ThresholdProfile{} + } + return self.rpcParams +} + +func (self *CmdSetThreshold) PostprocessRpcParams() error { + return nil +} + +func (self *CmdSetThreshold) RpcResult() interface{} { + var s string + return &s +} From 1e320c6f7eb7f38e47986e8721bfb7d63e227c05 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 15:54:46 +0200 Subject: [PATCH 56/75] Add in console statqueue statqueue_set statqueue_remove --- console/statqueue.go | 66 +++++++++++++++++++++++++++++++++++++ console/statqueue_remove.go | 63 +++++++++++++++++++++++++++++++++++ console/statqueue_set.go | 63 +++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 console/statqueue.go create mode 100644 console/statqueue_remove.go create mode 100644 console/statqueue_set.go diff --git a/console/statqueue.go b/console/statqueue.go new file mode 100644 index 000000000..47ffe9c7f --- /dev/null +++ b/console/statqueue.go @@ -0,0 +1,66 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func init() { + c := &CmdGetStatQueue{ + name: "statqueue", + rpcMethod: "ApierV1.GetStatQueueProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdGetStatQueue struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdGetStatQueue) Name() string { + return self.name +} + +func (self *CmdGetStatQueue) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdGetStatQueue) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdGetStatQueue) PostprocessRpcParams() error { + return nil +} + +func (self *CmdGetStatQueue) RpcResult() interface{} { + atr := engine.StatQueueProfile{} + return &atr +} diff --git a/console/statqueue_remove.go b/console/statqueue_remove.go new file mode 100644 index 000000000..2587b840c --- /dev/null +++ b/console/statqueue_remove.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/utils" + +func init() { + c := &CmdRemoveStatQueue{ + name: "statqueue_remove", + rpcMethod: "ApierV1.RemStatQueueProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdRemoveStatQueue struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdRemoveStatQueue) Name() string { + return self.name +} + +func (self *CmdRemoveStatQueue) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdRemoveStatQueue) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdRemoveStatQueue) PostprocessRpcParams() error { + return nil +} + +func (self *CmdRemoveStatQueue) RpcResult() interface{} { + var s string + return &s +} diff --git a/console/statqueue_set.go b/console/statqueue_set.go new file mode 100644 index 000000000..3cd05e595 --- /dev/null +++ b/console/statqueue_set.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/engine" + +func init() { + c := &CmdSetStatQueue{ + name: "statqueue_set", + rpcMethod: "ApierV1.SetStatQueueProfile", + rpcParams: &engine.StatQueueProfile{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdSetStatQueue struct { + name string + rpcMethod string + rpcParams *engine.StatQueueProfile + *CommandExecuter +} + +func (self *CmdSetStatQueue) Name() string { + return self.name +} + +func (self *CmdSetStatQueue) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdSetStatQueue) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &engine.StatQueueProfile{} + } + return self.rpcParams +} + +func (self *CmdSetStatQueue) PostprocessRpcParams() error { + return nil +} + +func (self *CmdSetStatQueue) RpcResult() interface{} { + var s string + return &s +} From 0962303baaffbcf1c581bc1bf8b48b4ef0a0586e Mon Sep 17 00:00:00 2001 From: TeoV Date: Sun, 19 Nov 2017 12:25:30 +0200 Subject: [PATCH 57/75] Add filter and resource in console --- console/filter.go | 66 ++++++++++++++++++++++++++++++++++++++ console/filter_remove.go | 63 ++++++++++++++++++++++++++++++++++++ console/filter_set.go | 63 ++++++++++++++++++++++++++++++++++++ console/resource.go | 66 ++++++++++++++++++++++++++++++++++++++ console/resource_remove.go | 63 ++++++++++++++++++++++++++++++++++++ console/resource_set.go | 63 ++++++++++++++++++++++++++++++++++++ 6 files changed, 384 insertions(+) create mode 100644 console/filter.go create mode 100644 console/filter_remove.go create mode 100644 console/filter_set.go create mode 100644 console/resource.go create mode 100644 console/resource_remove.go create mode 100644 console/resource_set.go diff --git a/console/filter.go b/console/filter.go new file mode 100644 index 000000000..035e7e9d9 --- /dev/null +++ b/console/filter.go @@ -0,0 +1,66 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func init() { + c := &CmdGetFilter{ + name: "filter", + rpcMethod: "ApierV1.GetFilter", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdGetFilter struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdGetFilter) Name() string { + return self.name +} + +func (self *CmdGetFilter) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdGetFilter) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdGetFilter) PostprocessRpcParams() error { + return nil +} + +func (self *CmdGetFilter) RpcResult() interface{} { + atr := engine.Filter{} + return &atr +} diff --git a/console/filter_remove.go b/console/filter_remove.go new file mode 100644 index 000000000..c52861aad --- /dev/null +++ b/console/filter_remove.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/utils" + +func init() { + c := &CmdRemoveFilter{ + name: "filter_remove", + rpcMethod: "ApierV1.RemFilter", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdRemoveFilter struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdRemoveFilter) Name() string { + return self.name +} + +func (self *CmdRemoveFilter) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdRemoveFilter) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdRemoveFilter) PostprocessRpcParams() error { + return nil +} + +func (self *CmdRemoveFilter) RpcResult() interface{} { + var s string + return &s +} diff --git a/console/filter_set.go b/console/filter_set.go new file mode 100644 index 000000000..29edfe8fe --- /dev/null +++ b/console/filter_set.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/engine" + +func init() { + c := &CmdSetFilter{ + name: "filter_set", + rpcMethod: "ApierV1.SetFilter", + rpcParams: &engine.Filter{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdSetFilter struct { + name string + rpcMethod string + rpcParams *engine.Filter + *CommandExecuter +} + +func (self *CmdSetFilter) Name() string { + return self.name +} + +func (self *CmdSetFilter) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdSetFilter) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &engine.Filter{} + } + return self.rpcParams +} + +func (self *CmdSetFilter) PostprocessRpcParams() error { + return nil +} + +func (self *CmdSetFilter) RpcResult() interface{} { + var s string + return &s +} diff --git a/console/resource.go b/console/resource.go new file mode 100644 index 000000000..3fec3c6d2 --- /dev/null +++ b/console/resource.go @@ -0,0 +1,66 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func init() { + c := &CmdGetResource{ + name: "resource", + rpcMethod: "ApierV1.GetResourceProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdGetResource struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdGetResource) Name() string { + return self.name +} + +func (self *CmdGetResource) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdGetResource) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdGetResource) PostprocessRpcParams() error { + return nil +} + +func (self *CmdGetResource) RpcResult() interface{} { + atr := engine.ResourceProfile{} + return &atr +} diff --git a/console/resource_remove.go b/console/resource_remove.go new file mode 100644 index 000000000..dc34f19ed --- /dev/null +++ b/console/resource_remove.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/utils" + +func init() { + c := &CmdRemoveResource{ + name: "resource_remove", + rpcMethod: "ApierV1.RemResourceProfile", + rpcParams: &utils.TenantID{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdRemoveResource struct { + name string + rpcMethod string + rpcParams *utils.TenantID + *CommandExecuter +} + +func (self *CmdRemoveResource) Name() string { + return self.name +} + +func (self *CmdRemoveResource) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdRemoveResource) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &utils.TenantID{} + } + return self.rpcParams +} + +func (self *CmdRemoveResource) PostprocessRpcParams() error { + return nil +} + +func (self *CmdRemoveResource) RpcResult() interface{} { + var s string + return &s +} diff --git a/console/resource_set.go b/console/resource_set.go new file mode 100644 index 000000000..2fc932e4b --- /dev/null +++ b/console/resource_set.go @@ -0,0 +1,63 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package console + +import "github.com/cgrates/cgrates/engine" + +func init() { + c := &CmdSetResource{ + name: "resource_set", + rpcMethod: "ApierV1.SetResourceProfile", + rpcParams: &engine.ResourceProfile{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdSetResource struct { + name string + rpcMethod string + rpcParams *engine.ResourceProfile + *CommandExecuter +} + +func (self *CmdSetResource) Name() string { + return self.name +} + +func (self *CmdSetResource) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdSetResource) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &engine.ResourceProfile{} + } + return self.rpcParams +} + +func (self *CmdSetResource) PostprocessRpcParams() error { + return nil +} + +func (self *CmdSetResource) RpcResult() interface{} { + var s string + return &s +} From 01b13ad9fd4da48ccc4081fec7056da68eb882d9 Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 19 Nov 2017 19:09:14 +0100 Subject: [PATCH 58/75] RadiusAgent - process usage in request as string instead of time duration, adding dictionary.microsoft for further CHAP development, updated radigo with octets support --- agents/radagent.go | 13 +- cmd/cgr-engine/cgr-engine.go | 3 +- data/radius/dict/dictionary.kamailio | 20 +-- data/radius/dict/dictionary.microsoft | 170 ++++++++++++++++++++++++++ glide.lock | 2 +- 5 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 data/radius/dict/dictionary.microsoft diff --git a/agents/radagent.go b/agents/radagent.go index d4119d8eb..235942d6e 100644 --- a/agents/radagent.go +++ b/agents/radagent.go @@ -47,6 +47,8 @@ const ( func NewRadiusAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection) (ra *RadiusAgent, err error) { dts := make(map[string]*radigo.Dictionary, len(cgrCfg.RadiusAgentCfg().ClientDictionaries)) for clntID, dictPath := range cgrCfg.RadiusAgentCfg().ClientDictionaries { + utils.Logger.Info(fmt.Sprintf( + " Loading dictionary for clientID: <%s> out of path <%s>", clntID, dictPath)) if dts[clntID], err = radigo.NewDictionaryFromFolderWithRFC2865(dictPath); err != nil { return } @@ -177,12 +179,17 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor, processorVars[MetaCGRError] = err.Error() return } - if reqUsage, has := smgEv[utils.USAGE]; !has { // usage was not requested, decide based on 0 + if reqUsageStr, has := smgEv[utils.USAGE]; !has { // usage was not requested, decide based on 0 if maxUsage == 0 { reply.Code = radigo.AccessReject } - } else if reqUsage.(time.Duration) < maxUsage { - reply.Code = radigo.AccessReject + } else { // usage requested + if reqUsage, err := utils.ParseDurationWithSecs(reqUsageStr.(string)); err != nil { + processorVars[MetaCGRError] = err.Error() + return false, err + } else if reqUsage < maxUsage { + reply.Code = radigo.AccessReject + } } case MetaRadAcctStart: err = ra.smg.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage) diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 2ff1bc6d8..0a198cb95 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -263,7 +263,8 @@ func startRadiusAgent(internalSMGChan chan *sessionmanager.SMGeneric, exitChan c }(internalSMGChan, smgChan) var smgConn *rpcclient.RpcClientPool if len(cfg.RadiusAgentCfg().SMGenericConns) != 0 { - smgConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, + smgConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, + cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RadiusAgentCfg().SMGenericConns, smgChan, cfg.InternalTtl) if err != nil { utils.Logger.Crit(fmt.Sprintf(" Could not connect to SMG: %s", err.Error())) diff --git a/data/radius/dict/dictionary.kamailio b/data/radius/dict/dictionary.kamailio index 131bff30b..148dec072 100644 --- a/data/radius/dict/dictionary.kamailio +++ b/data/radius/dict/dictionary.kamailio @@ -40,16 +40,16 @@ ATTRIBUTE Sip-CC 212 string ATTRIBUTE Sip-RPId 213 string ATTRIBUTE Digest-Response 206 string ATTRIBUTE Digest-Attributes 207 string -ATTRIBUTE Digest-Realm 1063 string -ATTRIBUTE Digest-Nonce 1064 string -ATTRIBUTE Digest-Method 1065 string -ATTRIBUTE Digest-URI 1066 string -ATTRIBUTE Digest-QOP 1067 string -ATTRIBUTE Digest-Algorithm 1068 string -ATTRIBUTE Digest-Body-Digest 1069 string -ATTRIBUTE Digest-CNonce 1070 string -ATTRIBUTE Digest-Nonce-Count 1071 string -ATTRIBUTE Digest-User-Name 1072 string +#ATTRIBUTE Digest-Realm 1063 string +#ATTRIBUTE Digest-Nonce 1064 string +#ATTRIBUTE Digest-Method 1065 string +#ATTRIBUTE Digest-URI 1066 string +#ATTRIBUTE Digest-QOP 1067 string +#ATTRIBUTE Digest-Algorithm 1068 string +#ATTRIBUTE Digest-Body-Digest 1069 string +#ATTRIBUTE Digest-CNonce 1070 string +#ATTRIBUTE Digest-Nonce-Count 1071 string +#ATTRIBUTE Digest-User-Name 1072 string ATTRIBUTE Ascend-User-Acct-Time 143 integer ATTRIBUTE Sip-Uri-User 208 string # Proprietary, auth_radius diff --git a/data/radius/dict/dictionary.microsoft b/data/radius/dict/dictionary.microsoft new file mode 100644 index 000000000..734559162 --- /dev/null +++ b/data/radius/dict/dictionary.microsoft @@ -0,0 +1,170 @@ +# -*- text -*- +# Copyright (C) 2015 The FreeRADIUS Server project and contributors +# +# Microsoft's VSA's, from RFC 2548 +# +# $Id$ +# + +VENDOR Microsoft 311 + +BEGIN-VENDOR Microsoft +ATTRIBUTE MS-CHAP-Response 1 octets[50] +ATTRIBUTE MS-CHAP-Error 2 string +ATTRIBUTE MS-CHAP-CPW-1 3 octets[70] +ATTRIBUTE MS-CHAP-CPW-2 4 octets[84] +ATTRIBUTE MS-CHAP-LM-Enc-PW 5 octets +ATTRIBUTE MS-CHAP-NT-Enc-PW 6 octets +ATTRIBUTE MS-MPPE-Encryption-Policy 7 integer + +VALUE MS-MPPE-Encryption-Policy Encryption-Allowed 1 +VALUE MS-MPPE-Encryption-Policy Encryption-Required 2 + +# This is referred to as both singular and plural in the RFC. +# Plural seems to make more sense. +ATTRIBUTE MS-MPPE-Encryption-Type 8 integer +ATTRIBUTE MS-MPPE-Encryption-Types 8 integer + +VALUE MS-MPPE-Encryption-Types RC4-40bit-Allowed 1 +VALUE MS-MPPE-Encryption-Types RC4-128bit-Allowed 2 +VALUE MS-MPPE-Encryption-Types RC4-40or128-bit-Allowed 6 + +ATTRIBUTE MS-RAS-Vendor 9 integer # content is Vendor-ID +ATTRIBUTE MS-CHAP-Domain 10 string +ATTRIBUTE MS-CHAP-Challenge 11 octets +ATTRIBUTE MS-CHAP-MPPE-Keys 12 octets[24] encrypt=1 +ATTRIBUTE MS-BAP-Usage 13 integer +ATTRIBUTE MS-Link-Utilization-Threshold 14 integer # values are 1-100 +ATTRIBUTE MS-Link-Drop-Time-Limit 15 integer +ATTRIBUTE MS-MPPE-Send-Key 16 octets encrypt=2 +ATTRIBUTE MS-MPPE-Recv-Key 17 octets encrypt=2 +ATTRIBUTE MS-RAS-Version 18 string +ATTRIBUTE MS-Old-ARAP-Password 19 octets +ATTRIBUTE MS-New-ARAP-Password 20 octets +ATTRIBUTE MS-ARAP-PW-Change-Reason 21 integer + +ATTRIBUTE MS-Filter 22 octets +ATTRIBUTE MS-Acct-Auth-Type 23 integer +ATTRIBUTE MS-Acct-EAP-Type 24 integer + +ATTRIBUTE MS-CHAP2-Response 25 octets[50] +ATTRIBUTE MS-CHAP2-Success 26 octets +ATTRIBUTE MS-CHAP2-CPW 27 octets[68] + +ATTRIBUTE MS-Primary-DNS-Server 28 ipaddr +ATTRIBUTE MS-Secondary-DNS-Server 29 ipaddr +ATTRIBUTE MS-Primary-NBNS-Server 30 ipaddr +ATTRIBUTE MS-Secondary-NBNS-Server 31 ipaddr + +#ATTRIBUTE MS-ARAP-Challenge 33 octets[8] + +## MS-RNAP +# +# http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-RNAP%5D.pdf + +ATTRIBUTE MS-RAS-Client-Name 34 string +ATTRIBUTE MS-RAS-Client-Version 35 string +ATTRIBUTE MS-Quarantine-IPFilter 36 octets +ATTRIBUTE MS-Quarantine-Session-Timeout 37 integer +ATTRIBUTE MS-User-Security-Identity 40 string +ATTRIBUTE MS-Identity-Type 41 integer +ATTRIBUTE MS-Service-Class 42 string +ATTRIBUTE MS-Quarantine-User-Class 44 string +ATTRIBUTE MS-Quarantine-State 45 integer +ATTRIBUTE MS-Quarantine-Grace-Time 46 integer +ATTRIBUTE MS-Network-Access-Server-Type 47 integer +ATTRIBUTE MS-AFW-Zone 48 integer + +VALUE MS-AFW-Zone MS-AFW-Zone-Boundary-Policy 1 +VALUE MS-AFW-Zone MS-AFW-Zone-Unprotected-Policy 2 +VALUE MS-AFW-Zone MS-AFW-Zone-Protected-Policy 3 + +ATTRIBUTE MS-AFW-Protection-Level 49 integer + +VALUE MS-AFW-Protection-Level HECP-Response-Sign-Only 1 +VALUE MS-AFW-Protection-Level HECP-Response-Sign-And-Encrypt 2 + +ATTRIBUTE MS-Machine-Name 50 string +ATTRIBUTE MS-IPv6-Filter 51 octets +ATTRIBUTE MS-IPv4-Remediation-Servers 52 octets +ATTRIBUTE MS-IPv6-Remediation-Servers 53 octets +ATTRIBUTE MS-RNAP-Not-Quarantine-Capable 54 integer + +VALUE MS-RNAP-Not-Quarantine-Capable SoH-Sent 0 +VALUE MS-RNAP-Not-Quarantine-Capable SoH-Not-Sent 1 + +ATTRIBUTE MS-Quarantine-SOH 55 octets +ATTRIBUTE MS-RAS-Correlation 56 octets + +# Or this might be 56? +ATTRIBUTE MS-Extended-Quarantine-State 57 integer + +ATTRIBUTE MS-HCAP-User-Groups 58 string +ATTRIBUTE MS-HCAP-Location-Group-Name 59 string +ATTRIBUTE MS-HCAP-User-Name 60 string +ATTRIBUTE MS-User-IPv4-Address 61 ipaddr +ATTRIBUTE MS-User-IPv6-Address 62 ipv6addr +ATTRIBUTE MS-TSG-Device-Redirection 63 integer + +# +# Integer Translations +# + +# MS-BAP-Usage Values + +VALUE MS-BAP-Usage Not-Allowed 0 +VALUE MS-BAP-Usage Allowed 1 +VALUE MS-BAP-Usage Required 2 + +# MS-ARAP-Password-Change-Reason Values + +VALUE MS-ARAP-PW-Change-Reason Just-Change-Password 1 +VALUE MS-ARAP-PW-Change-Reason Expired-Password 2 +VALUE MS-ARAP-PW-Change-Reason Admin-Requires-Password-Change 3 +VALUE MS-ARAP-PW-Change-Reason Password-Too-Short 4 + +# MS-Acct-Auth-Type Values + +VALUE MS-Acct-Auth-Type PAP 1 +VALUE MS-Acct-Auth-Type CHAP 2 +VALUE MS-Acct-Auth-Type MS-CHAP-1 3 +VALUE MS-Acct-Auth-Type MS-CHAP-2 4 +VALUE MS-Acct-Auth-Type EAP 5 + +# MS-Acct-EAP-Type Values + +VALUE MS-Acct-EAP-Type MD5 4 +VALUE MS-Acct-EAP-Type OTP 5 +VALUE MS-Acct-EAP-Type Generic-Token-Card 6 +VALUE MS-Acct-EAP-Type TLS 13 + +# MS-Identity-Type Values + +VALUE MS-Identity-Type Machine-Health-Check 1 +VALUE MS-Identity-Type Ignore-User-Lookup-Failure 2 + +# MS-Quarantine-State Values + +VALUE MS-Quarantine-State Full-Access 0 +VALUE MS-Quarantine-State Quarantine 1 +VALUE MS-Quarantine-State Probation 2 + +# MS-Network-Access-Server-Type Values + +VALUE MS-Network-Access-Server-Type Unspecified 0 +VALUE MS-Network-Access-Server-Type Terminal-Server-Gateway 1 +VALUE MS-Network-Access-Server-Type Remote-Access-Server 2 +VALUE MS-Network-Access-Server-Type DHCP-Server 3 +VALUE MS-Network-Access-Server-Type Wireless-Access-Point 4 +VALUE MS-Network-Access-Server-Type HRA 5 +VALUE MS-Network-Access-Server-Type HCAP-Server 6 + +# MS-Extended-Quarantine-State Values + +VALUE MS-Extended-Quarantine-State Transition 1 +VALUE MS-Extended-Quarantine-State Infected 2 +VALUE MS-Extended-Quarantine-State Unknown 3 +VALUE MS-Extended-Quarantine-State No-Data 4 + +END-VENDOR Microsoft + diff --git a/glide.lock b/glide.lock index a1ec4d151..f5638c876 100644 --- a/glide.lock +++ b/glide.lock @@ -20,7 +20,7 @@ imports: - name: github.com/cgrates/osipsdagram version: 3d6beed663452471dec3ca194137a30d379d9e8f - name: github.com/cgrates/radigo - version: 4351b1d135e822472a2759ae1c95f103cf51df60 + version: 69d4269e21990c0f120b8e60d5b75d533db7f3dd - name: github.com/cgrates/rpcclient version: dddae42e9344e877627cd4b7aba075d63b452c0b - name: github.com/ChrisTrenkamp/goxpath From b8215b814c8c25f5b5f9e2605855fcd7bdb30aa2 Mon Sep 17 00:00:00 2001 From: edwardro22 Date: Sun, 19 Nov 2017 19:52:00 +0000 Subject: [PATCH 59/75] Updated cgr-migrator params and refactored GetTpIds --- cmd/cgr-migrator/cgr-migrator.go | 25 ++++++------ engine/storage_csv.go | 2 +- engine/storage_mongo_stordb.go | 6 +-- engine/storage_sql.go | 66 +++++++++++++++----------------- 4 files changed, 46 insertions(+), 53 deletions(-) diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index b97af5166..80f5b2b89 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -52,22 +52,21 @@ var ( outStorDBUser = flag.String("out_stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") outStorDBPass = flag.String("out_stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") - inDataDBType = flag.String("in_datadb_type", "", "The type of the DataDb Database ") - inDataDBHost = flag.String("in_datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") - inDataDBPort = flag.String("in_datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") - inDataDBName = flag.String("in_datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") - inDataDBUser = flag.String("in_datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") - inDataDBPass = flag.String("in_datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") + inDataDBType = flag.String("datadb_type", "", "The type of the DataDb Database ") + inDataDBHost = flag.String("datadb_host", config.CgrConfig().DataDbHost, "The DataDb host to connect to.") + inDataDBPort = flag.String("datadb_port", config.CgrConfig().DataDbPort, "The DataDb port to bind to.") + inDataDBName = flag.String("datadb_name", config.CgrConfig().DataDbName, "The name/number of the DataDb to connect to.") + inDataDBUser = flag.String("datadb_user", config.CgrConfig().DataDbUser, "The DataDb user to sign in as.") + inDataDBPass = flag.String("datadb_passwd", config.CgrConfig().DataDbPass, "The DataDb user's password.") - inStorDBType = flag.String("in_stordb_type", "", "The type of the storDb Database ") - inStorDBHost = flag.String("in_stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") - inStorDBPort = flag.String("in_stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") - inStorDBName = flag.String("in_stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") - inStorDBUser = flag.String("in_stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") - inStorDBPass = flag.String("in_stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") + inStorDBType = flag.String("stordb_type", "", "The type of the storDb Database ") + inStorDBHost = flag.String("stordb_host", config.CgrConfig().StorDBHost, "The storDb host to connect to.") + inStorDBPort = flag.String("stordb_port", config.CgrConfig().StorDBPort, "The storDb port to bind to.") + inStorDBName = flag.String("stordb_name", config.CgrConfig().StorDBName, "The name/number of the storDb to connect to.") + inStorDBUser = flag.String("stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") + inStorDBPass = flag.String("stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") - inLoadHistorySize = flag.Int("in_load_history_size", 0, "Limit the number of records in the load history") dbDataEncoding = flag.String("dbData_encoding", config.CgrConfig().DBDataEncoding, "The encoding used to store object Data in strings") inDBDataEncoding = flag.String("in_dbData_encoding", "", "The encoding used to store object Data in strings") diff --git a/engine/storage_csv.go b/engine/storage_csv.go index 8359a36b5..d6e3fc9da 100755 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -705,7 +705,7 @@ func (csvs *CSVStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return tpFilter.AsTPFilter(), nil } -func (csvs *CSVStorage) GetTpIds(x string) ([]string, error) { +func (csvs *CSVStorage) GetTpIds(colName string) ([]string, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index b9cbb8c61..2e52f9e86 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -28,15 +28,15 @@ import ( "time" ) -func (ms *MongoStorage) GetTpIds(colname string) ([]string, error) { +func (ms *MongoStorage) GetTpIds(colName string) ([]string, error) { tpidMap := make(map[string]bool) session := ms.session.Copy() db := session.DB(ms.db) defer session.Close() var tpids []string var err error - cols := []string{colname} - if colname == "" { + cols := []string{colName} + if colName == "" { cols, err = db.CollectionNames() if err != nil { return nil, err diff --git a/engine/storage_sql.go b/engine/storage_sql.go index e9a5cb8a0..1fcbac0c7 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -120,45 +120,39 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { // update // Return a list with all TPids defined in the system, even if incomplete, isolated in some table. -func (self *SQLStorage) GetTpIds(colname string) ([]string, error) { +func (self *SQLStorage) GetTpIds(colName string) ([]string, error) { var rows *sql.Rows var err error - if colname != "" { - rows, err = self.Db.Query( - fmt.Sprintf(" (SELECT tpid FROM %s)", colname)) - if err != nil { - return nil, err - } - defer rows.Close() - } else { - rows, err = self.Db.Query( - fmt.Sprintf( - "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", - utils.TBLTPTimings, - utils.TBLTPDestinations, - utils.TBLTPRates, - utils.TBLTPDestinationRates, - utils.TBLTPRatingPlans, - utils.TBLTPRateProfiles, - utils.TBLTPSharedGroups, - utils.TBLTPCdrStats, - utils.TBLTPLcrs, - utils.TBLTPActions, - utils.TBLTPActionTriggers, - utils.TBLTPAccountActions, - utils.TBLTPDerivedChargers, - utils.TBLTPUsers, - utils.TBLTPAliases, - utils.TBLTPResources, - utils.TBLTPStats, - utils.TBLTPThresholds, - utils.TBLTPFilters, - utils.TBLTPActionPlans)) - if err != nil { - return nil, err - } - defer rows.Close() + qryStr := fmt.Sprintf(" (SELECT tpid FROM %s)", colName) + if colName == "" { + qryStr = fmt.Sprintf( + "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", + utils.TBLTPTimings, + utils.TBLTPDestinations, + utils.TBLTPRates, + utils.TBLTPDestinationRates, + utils.TBLTPRatingPlans, + utils.TBLTPRateProfiles, + utils.TBLTPSharedGroups, + utils.TBLTPCdrStats, + utils.TBLTPLcrs, + utils.TBLTPActions, + utils.TBLTPActionTriggers, + utils.TBLTPAccountActions, + utils.TBLTPDerivedChargers, + utils.TBLTPUsers, + utils.TBLTPAliases, + utils.TBLTPResources, + utils.TBLTPStats, + utils.TBLTPThresholds, + utils.TBLTPFilters, + utils.TBLTPActionPlans) } + rows, err = self.Db.Query(qryStr) + if err != nil { + return nil, err + } + defer rows.Close() ids := make([]string, 0) i := 0 for rows.Next() { From 8bca0a2d64aaf92cd3158aa145ec88293adf81bc Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 20 Nov 2017 09:55:23 +0100 Subject: [PATCH 60/75] Missing import --- engine/lcrs.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 engine/lcrs.go diff --git a/engine/lcrs.go b/engine/lcrs.go new file mode 100644 index 000000000..dcf9d7dad --- /dev/null +++ b/engine/lcrs.go @@ -0,0 +1,37 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package engine + +import ( + "github.com/cgrates/cgrates/utils" +) + +// LCRProfile represents the configuration of a LCR profile +type LCRProfile struct { + Tenant string + ID string // LCR Profile ID + FilterIDs []string + ActivationInterval *utils.ActivationInterval // Activation interval + Strategy string // LCR Strategy used when computing + StrategyParams []string + SupplierID string + RatingPlanIDs []string // RatingPlans used when computing price + StatIDs []string // StatProfiles queried in case of QoS based strategies + Weight float64 +} From c07a264a53b3312976f8f053be2bf8c394792723 Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 20 Nov 2017 10:57:46 +0200 Subject: [PATCH 61/75] Adding space for logger stdout messages --- utils/logger.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/logger.go b/utils/logger.go index 7a35d6769..d8f3166cb 100644 --- a/utils/logger.go +++ b/utils/logger.go @@ -123,7 +123,7 @@ func (sl *StdLogger) Alert(m string) (err error) { if sl.syslog != nil { sl.syslog.Alert(m) } else { - log.Print("[ALERT]" + m) + log.Print("[ALERT] " + m) } return } @@ -136,7 +136,7 @@ func (sl *StdLogger) Crit(m string) (err error) { if sl.syslog != nil { sl.syslog.Crit(m) } else { - log.Print("[CRITICAL]" + m) + log.Print("[CRITICAL] " + m) } return } @@ -149,7 +149,7 @@ func (sl *StdLogger) Debug(m string) (err error) { if sl.syslog != nil { sl.syslog.Debug(m) } else { - log.Print("[DEBUG]" + m) + log.Print("[DEBUG] " + m) } return } @@ -162,7 +162,7 @@ func (sl *StdLogger) Emerg(m string) (err error) { if sl.syslog != nil { sl.syslog.Emerg(m) } else { - log.Print("[EMERGENCY]" + m) + log.Print("[EMERGENCY] " + m) } return } @@ -175,7 +175,7 @@ func (sl *StdLogger) Err(m string) (err error) { if sl.syslog != nil { sl.syslog.Err(m) } else { - log.Print("[ERROR]" + m) + log.Print("[ERROR] " + m) } return } @@ -188,7 +188,7 @@ func (sl *StdLogger) Info(m string) (err error) { if sl.syslog != nil { sl.syslog.Info(m) } else { - log.Print("[INFO]" + m) + log.Print("[INFO] " + m) } return } @@ -201,7 +201,7 @@ func (sl *StdLogger) Notice(m string) (err error) { if sl.syslog != nil { sl.syslog.Notice(m) } else { - log.Print("[NOTICE]" + m) + log.Print("[NOTICE] " + m) } return } @@ -215,7 +215,7 @@ func (sl *StdLogger) Warning(m string) (err error) { if sl.syslog != nil { sl.syslog.Warning(m) } else { - log.Print("[WARNING]" + m) + log.Print("[WARNING] " + m) } return } From 9d931c29c33301061563e6de6c477d6b49d504aa Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 20 Nov 2017 10:18:59 +0100 Subject: [PATCH 62/75] Sample Lcr.csv in tariffplans/tutorial --- data/tariffplans/tutorial/Lcr.csv | 2 ++ data/tariffplans/tutorial/Resources.csv | 0 data/tariffplans/tutorial/Stats.csv | 0 3 files changed, 2 insertions(+) create mode 100644 data/tariffplans/tutorial/Lcr.csv mode change 100755 => 100644 data/tariffplans/tutorial/Resources.csv mode change 100755 => 100644 data/tariffplans/tutorial/Stats.csv diff --git a/data/tariffplans/tutorial/Lcr.csv b/data/tariffplans/tutorial/Lcr.csv new file mode 100644 index 000000000..60c518921 --- /dev/null +++ b/data/tariffplans/tutorial/Lcr.csv @@ -0,0 +1,2 @@ +#Tenant,ID,FilterIDs,ActivationInterval,Strategy,StrategyParams,SupplierID,RatingPlanIDs,StatIDs,Weight +cgrates.org,LCR_1,FLTR_ACNT_dan;FLTR_DST_DE,2014-07-29T15:00:00Z,*lowest_cost,,supplier1,RPL_1,,20 diff --git a/data/tariffplans/tutorial/Resources.csv b/data/tariffplans/tutorial/Resources.csv old mode 100755 new mode 100644 diff --git a/data/tariffplans/tutorial/Stats.csv b/data/tariffplans/tutorial/Stats.csv old mode 100755 new mode 100644 From 47ec619a445731702e1b82515b187ea07c01cd68 Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 20 Nov 2017 13:11:02 +0200 Subject: [PATCH 63/75] LCRProfile (1) --- engine/datamanager.go | 45 ++++++++++- engine/lcrs.go | 5 ++ engine/libtest.go | 6 +- engine/model_helpers.go | 139 ++++++++++++++++++++++++++++++++- engine/models.go | 16 ++++ engine/storage_csv.go | 40 ++++++++-- engine/storage_interface.go | 5 ++ engine/storage_map.go | 32 ++++++++ engine/storage_mongo_datadb.go | 97 ++++++++++++++++------- engine/storage_mongo_stordb.go | 31 ++++++++ engine/storage_redis.go | 34 +++++++- engine/storage_sql.go | 22 ++++++ engine/tp_reader.go | 96 ++++++++++++++++++++++- utils/apitpdata.go | 14 ++++ utils/consts.go | 6 ++ 15 files changed, 543 insertions(+), 45 deletions(-) diff --git a/engine/datamanager.go b/engine/datamanager.go index bc42d3ad1..715f34d48 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -38,7 +38,7 @@ func (dm *DataManager) DataDB() DataDB { return dm.dataDB } -func (dm *DataManager) LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aaPlIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rpIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string) (err error) { +func (dm *DataManager) LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aaPlIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rpIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string) (err error) { if dm.DataDB().GetStorageType() == utils.MAPSTOR { if dm.cacheCfg == nil { return @@ -49,7 +49,7 @@ func (dm *DataManager) LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, utils.RATING_PLAN_PREFIX, utils.RATING_PROFILE_PREFIX, utils.LCR_PREFIX, utils.CDR_STATS_PREFIX, utils.ACTION_PREFIX, utils.ACTION_PLAN_PREFIX, utils.ACTION_TRIGGER_PREFIX, utils.SHARED_GROUP_PREFIX, utils.ALIASES_PREFIX, utils.REVERSE_ALIASES_PREFIX, utils.StatQueuePrefix, utils.StatQueueProfilePrefix, - utils.ThresholdPrefix, utils.ThresholdProfilePrefix, utils.FilterPrefix}, k) && cacheCfg.Precache { + utils.ThresholdPrefix, utils.ThresholdProfilePrefix, utils.FilterPrefix, utils.LCRProfilePrefix}, k) && cacheCfg.Precache { if err := dm.PreloadCacheForPrefix(k); err != nil && err != utils.ErrInvalidKey { return err } @@ -78,6 +78,7 @@ func (dm *DataManager) LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, utils.ThresholdPrefix: thIDs, utils.ThresholdProfilePrefix: thpIDs, utils.FilterPrefix: fltrIDs, + utils.LCRProfilePrefix: lcrPrfIDs, } { if err = dm.CacheDataFromDB(key, ids, false); err != nil { return @@ -134,7 +135,8 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, - utils.FilterPrefix}, prfx) { + utils.FilterPrefix, + utils.LCRProfilePrefix}, prfx) { return utils.NewCGRError(utils.MONGO, utils.MandatoryIEMissingCaps, utils.UnsupportedCachePrefix, @@ -220,6 +222,9 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b case utils.FilterPrefix: tntID := utils.NewTenantID(dataID) _, err = dm.GetFilter(tntID.Tenant, tntID.ID, true, utils.NonTransactional) + case utils.LCRProfilePrefix: + tntID := utils.NewTenantID(dataID) + _, err = dm.GetLCRProfile(tntID.Tenant, tntID.ID, true, utils.NonTransactional) } if err != nil { return utils.NewCGRError(utils.MONGO, @@ -815,3 +820,37 @@ func (dm *DataManager) GetCdrStats(key string) (cs *CdrStats, err error) { func (dm *DataManager) GetAllCdrStats() (css []*CdrStats, err error) { return dm.DataDB().GetAllCdrStatsDrv() } + +func (dm *DataManager) GetLCRProfile(tenant, id string, skipCache bool, transactionID string) (lcrprf *LCRProfile, err error) { + key := utils.LCRProfilePrefix + utils.ConcatenatedKey(tenant, id) + if !skipCache { + if x, ok := cache.Get(key); ok { + if x == nil { + return nil, utils.ErrNotFound + } + return x.(*LCRProfile), nil + } + } + lcrprf, err = dm.dataDB.GetLCRProfileDrv(tenant, id) + if err != nil { + if err == utils.ErrNotFound { + cache.Set(key, nil, cacheCommit(transactionID), transactionID) + } + return nil, err + } + cache.Set(key, lcrprf, cacheCommit(transactionID), transactionID) + return +} + +func (dm *DataManager) SetLCRProfile(lcrprf *LCRProfile) (err error) { + return dm.DataDB().SetLCRProfileDrv(lcrprf) +} + +func (dm *DataManager) RemoveLCRProfile(tenant, id, transactionID string) (err error) { + if err = dm.DataDB().RemoveLCRProfileDrv(tenant, id); err != nil { + return + } + cache.RemKey(utils.LCRProfilePrefix+utils.ConcatenatedKey(tenant, id), + cacheCommit(transactionID), transactionID) + return +} diff --git a/engine/lcrs.go b/engine/lcrs.go index dcf9d7dad..cc9f0cf5e 100644 --- a/engine/lcrs.go +++ b/engine/lcrs.go @@ -35,3 +35,8 @@ type LCRProfile struct { StatIDs []string // StatProfiles queried in case of QoS based strategies Weight float64 } + +// TenantID returns unique identifier of the LCRProfile in a multi-tenant environment +func (rp *LCRProfile) TenantID() string { + return utils.ConcatenatedKey(rp.Tenant, rp.ID) +} diff --git a/engine/libtest.go b/engine/libtest.go index c121da537..31dc28216 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -34,15 +34,14 @@ import ( ) func InitDataDb(cfg *config.CGRConfig) error { - dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, - cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) + dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) if err != nil { return err } if err := dm.DataDB().Flush(""); err != nil { return err } - dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) // Write version before starting if err := SetDBVersions(dm.dataDB); err != nil { return err @@ -136,6 +135,7 @@ func LoadTariffPlanFromFolder(tpPath, timezone string, dm *DataManager, disable_ path.Join(tpPath, utils.StatsCsv), path.Join(tpPath, utils.ThresholdsCsv), path.Join(tpPath, utils.FiltersCsv), + path.Join(tpPath, utils.LCRCsv), ), "", timezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 8d984a078..57fbbd0a8 100755 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -2371,7 +2371,6 @@ func APItoModelTPFilter(th *utils.TPFilter) (mdls TpFilterS) { mdls = append(mdls, mdl) } return - } func APItoFilter(tpTH *utils.TPFilter, timezone string) (th *Filter, err error) { @@ -2419,3 +2418,141 @@ func FilterToTPFilter(f *Filter) (tpFltr *utils.TPFilter) { } return } + +type TpLCRProfiles []*TpLCRProfile + +func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { + mst := make(map[string]*utils.TPLCRProfile) + for _, tp := range tps { + th, found := mst[tp.ID] + if !found { + th = &utils.TPLCRProfile{ + TPid: tp.Tpid, + Tenant: tp.Tenant, + ID: tp.ID, + Strategy: tp.Strategy, + SupplierID: tp.SupplierID, + } + } + if tp.StrategyParams != "" { + strategyParamSplit := strings.Split(tp.StrategyParams, utils.INFIELD_SEP) + for _, strategyParam := range strategyParamSplit { + th.StrategyParams = append(th.StrategyParams, strategyParam) + } + } + if tp.RatingPlanIDs != "" { + ratingPlansIDsSplit := strings.Split(tp.RatingPlanIDs, utils.INFIELD_SEP) + for _, ratingPlanID := range ratingPlansIDsSplit { + th.RatingPlanIDs = append(th.RatingPlanIDs, ratingPlanID) + } + } + if tp.StatIDs != "" { + statIDsSplit := strings.Split(tp.StatIDs, utils.INFIELD_SEP) + for _, statID := range statIDsSplit { + th.StatIDs = append(th.StatIDs, statID) + } + } + if tp.Weight != 0 { + th.Weight = tp.Weight + } + if len(tp.ActivationInterval) != 0 { + th.ActivationInterval = new(utils.TPActivationInterval) + aiSplt := strings.Split(tp.ActivationInterval, utils.INFIELD_SEP) + if len(aiSplt) == 2 { + th.ActivationInterval.ActivationTime = aiSplt[0] + th.ActivationInterval.ExpiryTime = aiSplt[1] + } else if len(aiSplt) == 1 { + th.ActivationInterval.ActivationTime = aiSplt[0] + } + } + if tp.FilterIDs != "" { + filterSplit := strings.Split(tp.FilterIDs, utils.INFIELD_SEP) + for _, filter := range filterSplit { + th.FilterIDs = append(th.FilterIDs, filter) + } + } + + mst[tp.ID] = th + } + result = make([]*utils.TPLCRProfile, len(mst)) + i := 0 + for _, th := range mst { + result[i] = th + i++ + } + return +} + +func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRProfiles) { + if st != nil { + for i, fltr := range st.FilterIDs { + mdl := &TpLCRProfile{ + Tenant: st.Tenant, + Tpid: st.TPid, + ID: st.ID, + } + if i == 0 { + mdl.Strategy = st.Strategy + mdl.Weight = st.Weight + mdl.SupplierID = st.SupplierID + for i, val := range st.StrategyParams { + if i != 0 { + mdl.StrategyParams += utils.INFIELD_SEP + } + mdl.StrategyParams += val + } + for i, val := range st.RatingPlanIDs { + if i != 0 { + mdl.RatingPlanIDs += utils.INFIELD_SEP + } + mdl.RatingPlanIDs += val + } + for i, val := range st.StatIDs { + if i != 0 { + mdl.StatIDs += utils.INFIELD_SEP + } + mdl.StatIDs += val + } + if st.ActivationInterval != nil { + if st.ActivationInterval.ActivationTime != "" { + mdl.ActivationInterval = st.ActivationInterval.ActivationTime + } + if st.ActivationInterval.ExpiryTime != "" { + mdl.ActivationInterval += utils.INFIELD_SEP + st.ActivationInterval.ExpiryTime + } + } + } + mdl.FilterIDs = fltr + mdls = append(mdls, mdl) + } + } + return +} + +func APItoLCRProfile(tpTH *utils.TPLCRProfile, timezone string) (th *LCRProfile, err error) { + th = &LCRProfile{ + Tenant: tpTH.Tenant, + ID: tpTH.ID, + Strategy: tpTH.Strategy, + SupplierID: tpTH.SupplierID, + Weight: tpTH.Weight, + } + for _, stp := range tpTH.StrategyParams { + th.StrategyParams = append(th.StrategyParams, stp) + } + for _, fli := range tpTH.FilterIDs { + th.FilterIDs = append(th.FilterIDs, fli) + } + if tpTH.ActivationInterval != nil { + if th.ActivationInterval, err = tpTH.ActivationInterval.AsActivationInterval(timezone); err != nil { + return nil, err + } + } + for _, rpl := range tpTH.RatingPlanIDs { + th.RatingPlanIDs = append(th.RatingPlanIDs, rpl) + } + for _, sts := range tpTH.StatIDs { + th.StatIDs = append(th.StatIDs, sts) + } + return th, nil +} diff --git a/engine/models.go b/engine/models.go index 9bcc8d1d6..e218c3dac 100755 --- a/engine/models.go +++ b/engine/models.go @@ -519,3 +519,19 @@ type TBLVersion struct { func (t TBLVersion) TableName() string { return utils.TBLVersions } + +type TpLCRProfile struct { + PK uint `gorm:"primary_key"` + Tpid string + Tenant string `index:"0" re:""` + ID string `index:"1" re:""` + FilterIDs string `index:"2" re:""` + ActivationInterval string `index:"3" re:""` + Strategy string `index:"4" re:""` + StrategyParams string `index:"5" re:""` + SupplierID string `index:"6" re:""` + RatingPlanIDs string `index:"7" re:""` + StatIDs string `index:"8" re:""` + Weight float64 `index:"9" re:"\d+\.?\d*"` + CreatedAt time.Time +} diff --git a/engine/storage_csv.go b/engine/storage_csv.go index d6e3fc9da..7dad38c77 100755 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -33,26 +33,26 @@ type CSVStorage struct { readerFunc func(string, rune, int) (*csv.Reader, *os.File, error) // file names destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn, - sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string + sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string } func NewFileCSVStorage(sep rune, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, - actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string) *CSVStorage { + actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string) *CSVStorage { c := new(CSVStorage) c.sep = sep c.readerFunc = openFileCSVStorage c.destinationsFn, c.timingsFn, c.ratesFn, c.destinationratesFn, c.destinationratetimingsFn, c.ratingprofilesFn, - c.sharedgroupsFn, c.lcrFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn, c.cdrStatsFn, c.usersFn, c.aliasesFn, c.resProfilesFn, c.statsFn, c.thresholdsFn, c.filterFn = destinationsFn, timingsFn, - ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn + c.sharedgroupsFn, c.lcrFn, c.actionsFn, c.actiontimingsFn, c.actiontriggersFn, c.accountactionsFn, c.derivedChargersFn, c.cdrStatsFn, c.usersFn, c.aliasesFn, c.resProfilesFn, c.statsFn, c.thresholdsFn, c.filterFn, c.lcrProfilesFn = destinationsFn, timingsFn, + ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn return c } func NewStringCSVStorage(sep rune, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, lcrFn, - actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn string) *CSVStorage { + actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn string) *CSVStorage { c := NewFileCSVStorage(sep, destinationsFn, timingsFn, ratesFn, destinationratesFn, destinationratetimingsFn, - ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn) + ratingprofilesFn, sharedgroupsFn, lcrFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn, cdrStatsFn, usersFn, aliasesFn, resProfilesFn, statsFn, thresholdsFn, filterFn, lcrProfilesFn) c.readerFunc = openStringCSVStorage return c } @@ -705,6 +705,34 @@ func (csvs *CSVStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return tpFilter.AsTPFilter(), nil } +func (csvs *CSVStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile, error) { + csvReader, fp, err := csvs.readerFunc(csvs.lcrProfilesFn, csvs.sep, getColumnCount(TpLCR{})) + if err != nil { + //log.Print("Could not load lcr profiles file: ", err) + // allow writing of the other values + return nil, nil + } + if fp != nil { + defer fp.Close() + } + var tpResLimits TpLCRs + for record, err := csvReader.Read(); err != io.EOF; record, err = csvReader.Read() { + if err != nil { + log.Printf("bad line in %s, %s\n", csvs.lcrProfilesFn, err.Error()) + return nil, err + } + if tpResLimit, err := csvLoad(TpLCR{}, record); err != nil { + log.Print("error loading LCRProfiles: ", err) + return nil, err + } else { + tpLimit := tpResLimit.(TpLCR) + tpLimit.Tpid = tpid + tpResLimits = append(tpResLimits, &tpLimit) + } + } + return tpResLimits.AsTPLCRProfile(), nil +} + func (csvs *CSVStorage) GetTpIds(colName string) ([]string, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index d8b2e6297..3d96f851d 100755 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -128,6 +128,9 @@ type DataDB interface { GetFilterDrv(string, string) (*Filter, error) SetFilterDrv(*Filter) error RemoveFilterDrv(string, string) error + GetLCRProfileDrv(string, string) (*LCRProfile, error) + SetLCRProfileDrv(*LCRProfile) error + RemoveLCRProfileDrv(string, string) error } type StorDB interface { @@ -175,6 +178,7 @@ type LoadReader interface { GetTPStats(string, string) ([]*utils.TPStats, error) GetTPThresholds(string, string) ([]*utils.TPThreshold, error) GetTPFilters(string, string) ([]*utils.TPFilter, error) + GetTPLCRProfiles(string, string) ([]*utils.TPLCRProfile, error) } type LoadWriter interface { @@ -199,6 +203,7 @@ type LoadWriter interface { SetTPStats([]*utils.TPStats) error SetTPThresholds([]*utils.TPThreshold) error SetTPFilters([]*utils.TPFilter) error + SetTPLCRProfiles([]*utils.TPLCRProfile) error } // NewMarshaler returns the marshaler type selected by mrshlerStr diff --git a/engine/storage_map.go b/engine/storage_map.go index 55ae431ec..95f7c6896 100755 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -1380,7 +1380,39 @@ func (ms *MapStorage) RemoveFilterDrv(tenant, id string) (err error) { defer ms.mu.Unlock() key := utils.FilterPrefix + utils.ConcatenatedKey(tenant, id) delete(ms.dict, key) + return +} +func (ms *MapStorage) GetLCRProfileDrv(tenant, id string) (r *LCRProfile, err error) { + ms.mu.RLock() + defer ms.mu.RUnlock() + values, ok := ms.dict[utils.LCRProfilePrefix+utils.ConcatenatedKey(tenant, id)] + if !ok { + return nil, utils.ErrNotFound + } + err = ms.ms.Unmarshal(values, &r) + if err != nil { + return nil, err + } + return +} + +func (ms *MapStorage) SetLCRProfileDrv(r *LCRProfile) (err error) { + ms.mu.Lock() + defer ms.mu.Unlock() + result, err := ms.ms.Marshal(r) + if err != nil { + return err + } + ms.dict[utils.LCRProfilePrefix+utils.ConcatenatedKey(r.Tenant, r.ID)] = result + return +} + +func (ms *MapStorage) RemoveLCRProfileDrv(tenant, id string) (err error) { + ms.mu.Lock() + defer ms.mu.Unlock() + key := utils.LCRProfilePrefix + utils.ConcatenatedKey(tenant, id) + delete(ms.dict, key) return } diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index a5351057d..4a7231c49 100755 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -34,36 +34,37 @@ import ( ) const ( - colDst = "destinations" - colRds = "reverse_destinations" - colAct = "actions" - colApl = "action_plans" - colAAp = "account_action_plans" - colTsk = "tasks" - colAtr = "action_triggers" - colRpl = "rating_plans" - colRpf = "rating_profiles" - colAcc = "accounts" - colShg = "shared_groups" - colLcr = "lcr_rules" - colDcs = "derived_chargers" - colAls = "aliases" - colRCfgs = "reverse_aliases" - colStq = "stat_qeues" - colPbs = "pubsub" - colUsr = "users" - colCrs = "cdr_stats" - colLht = "load_history" - colVer = "versions" - colRsP = "resource_profiles" - colRFI = "request_filter_indexes" - colTmg = "timings" - colRes = "resources" - colSqs = "statqueues" - colSqp = "statqueue_profiles" - colTps = "threshold_profiles" - colThs = "thresholds" - colFlt = "filters" + colDst = "destinations" + colRds = "reverse_destinations" + colAct = "actions" + colApl = "action_plans" + colAAp = "account_action_plans" + colTsk = "tasks" + colAtr = "action_triggers" + colRpl = "rating_plans" + colRpf = "rating_profiles" + colAcc = "accounts" + colShg = "shared_groups" + colLcr = "lcr_rules" + colDcs = "derived_chargers" + colAls = "aliases" + colRCfgs = "reverse_aliases" + colStq = "stat_qeues" + colPbs = "pubsub" + colUsr = "users" + colCrs = "cdr_stats" + colLht = "load_history" + colVer = "versions" + colRsP = "resource_profiles" + colRFI = "request_filter_indexes" + colTmg = "timings" + colRes = "resources" + colSqs = "statqueues" + colSqp = "statqueue_profiles" + colTps = "threshold_profiles" + colThs = "thresholds" + colFlt = "filters" + colLcrPrf = "lcr_profiles" ) var ( @@ -573,6 +574,11 @@ func (ms *MongoStorage) GetKeysForPrefix(prefix string) (result []string, err er for iter.Next(&idResult) { result = append(result, utils.ThresholdProfilePrefix+utils.ConcatenatedKey(idResult.Tenant, idResult.Id)) } + case utils.LCRProfilePrefix: + iter := db.C(colLcrPrf).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"tenant": 1, "id": 1}).Iter() + for iter.Next(&idResult) { + result = append(result, utils.LCRProfilePrefix+utils.ConcatenatedKey(idResult.Tenant, idResult.Id)) + } default: err = fmt.Errorf("unsupported prefix in GetKeysForPrefix: %s", prefix) } @@ -615,6 +621,9 @@ func (ms *MongoStorage) HasDataDrv(category, subject string) (has bool, err erro case utils.FilterPrefix: count, err = db.C(colFlt).Find(bson.M{"id": subject}).Count() has = count > 0 + case utils.LCRProfilePrefix: + count, err = db.C(colLcrPrf).Find(bson.M{"id": subject}).Count() + has = count > 0 default: err = fmt.Errorf("unsupported category in HasData: %s", category) } @@ -1965,3 +1974,31 @@ func (ms *MongoStorage) RemoveFilterDrv(tenant, id string) (err error) { } return nil } + +func (ms *MongoStorage) GetLCRProfileDrv(tenant, id string) (r *LCRProfile, err error) { + session, col := ms.conn(colLcrPrf) + defer session.Close() + if err = col.Find(bson.M{"tenant": tenant, "id": id}).One(&r); err != nil { + if err == mgo.ErrNotFound { + err = utils.ErrNotFound + } + return nil, err + } + return +} + +func (ms *MongoStorage) SetLCRProfileDrv(r *LCRProfile) (err error) { + session, col := ms.conn(colLcrPrf) + defer session.Close() + _, err = col.Upsert(bson.M{"tenant": r.Tenant, "id": r.ID}, r) + return +} + +func (ms *MongoStorage) RemoveLCRProfileDrv(tenant, id string) (err error) { + session, col := ms.conn(colLcrPrf) + defer session.Close() + if err = col.Remove(bson.M{"tenant": tenant, "id": id}); err != nil { + return + } + return nil +} diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 2e52f9e86..866e6efc2 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1227,6 +1227,37 @@ func (ms *MongoStorage) SetTPFilters(tpTHs []*utils.TPFilter) (err error) { return } +func (ms *MongoStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile, error) { + filter := bson.M{ + "tpid": tpid, + } + if id != "" { + filter["id"] = id + } + var results []*utils.TPLCRProfile + session, col := ms.conn(utils.TBLTPLCRProfiles) + defer session.Close() + err := col.Find(filter).All(&results) + if len(results) == 0 { + return results, utils.ErrNotFound + } + return results, err +} + +func (ms *MongoStorage) SetTPLCRProfiles(tpTHs []*utils.TPLCRProfile) (err error) { + if len(tpTHs) == 0 { + return + } + session, col := ms.conn(utils.TBLTPLCRProfiles) + defer session.Close() + tx := col.Bulk() + for _, tp := range tpTHs { + tx.Upsert(bson.M{"tpid": tp.TPid, "id": tp.ID}, tp) + } + _, err = tx.Run() + return +} + func (ms *MongoStorage) GetVersions(itm string) (vrs Versions, err error) { session, col := ms.conn(colVer) defer session.Close() diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 7e7470b8a..039e291d8 100755 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -208,7 +208,8 @@ func (rs *RedisStorage) HasDataDrv(category, subject string) (bool, error) { switch category { case utils.DESTINATION_PREFIX, utils.RATING_PLAN_PREFIX, utils.RATING_PROFILE_PREFIX, utils.ACTION_PREFIX, utils.ACTION_PLAN_PREFIX, utils.ACCOUNT_PREFIX, utils.DERIVEDCHARGERS_PREFIX, - utils.ResourcesPrefix, utils.StatQueuePrefix, utils.ThresholdPrefix, utils.FilterPrefix: + utils.ResourcesPrefix, utils.StatQueuePrefix, utils.ThresholdPrefix, + utils.FilterPrefix, utils.LCRProfilePrefix: i, err := rs.Cmd("EXISTS", category+subject).Int() return i == 1, err } @@ -1520,6 +1521,37 @@ func (rs *RedisStorage) RemoveFilterDrv(tenant, id string) (err error) { return } +func (rs *RedisStorage) GetLCRProfileDrv(tenant, id string) (r *LCRProfile, err error) { + key := utils.LCRProfilePrefix + utils.ConcatenatedKey(tenant, id) + var values []byte + if values, err = rs.Cmd("GET", key).Bytes(); err != nil { + if err == redis.ErrRespNil { // did not find the destination + err = utils.ErrNotFound + } + return + } + if err = rs.ms.Unmarshal(values, &r); err != nil { + return + } + return +} + +func (rs *RedisStorage) SetLCRProfileDrv(r *LCRProfile) (err error) { + result, err := rs.ms.Marshal(r) + if err != nil { + return err + } + return rs.Cmd("SET", utils.LCRProfilePrefix+utils.ConcatenatedKey(r.Tenant, r.ID), result).Err +} + +func (rs *RedisStorage) RemoveLCRProfileDrv(tenant, id string) (err error) { + key := utils.LCRProfilePrefix + utils.ConcatenatedKey(tenant, id) + if err = rs.Cmd("DEL", key).Err; err != nil { + return + } + return +} + func (rs *RedisStorage) GetStorageType() string { return utils.REDIS } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 1fcbac0c7..83d0a1aab 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -689,6 +689,28 @@ func (self *SQLStorage) SetTPFilters(ths []*utils.TPFilter) error { return nil } +func (self *SQLStorage) SetTPLCRProfile(ths []*utils.TPLCRProfile) error { + if len(ths) == 0 { + return nil + } + tx := self.db.Begin() + for _, th := range ths { + // Remove previous + if err := tx.Where(&TpLCRProfile{Tpid: th.TPid, ID: th.ID}).Delete(TpLCRProfile{}).Error; err != nil { + tx.Rollback() + return err + } + for _, mst := range APItoModelTPLCRProfile(th) { + if err := tx.Save(&mst).Error; err != nil { + tx.Rollback() + return err + } + } + } + tx.Commit() + return nil +} + func (self *SQLStorage) SetSMCost(smc *SMCost) error { if smc.CostDetails == nil { return nil diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 79cab2b87..14eb4585c 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -57,15 +57,18 @@ type TpReader struct { sqProfiles map[utils.TenantID]*utils.TPStats thProfiles map[utils.TenantID]*utils.TPThreshold filters map[utils.TenantID]*utils.TPFilter + lcrProfiles map[utils.TenantID]*utils.TPLCRProfile resources []*utils.TenantID // IDs of resources which need creation based on resourceProfiles statQueues []*utils.TenantID // IDs of statQueues which need creation based on statQueueProfiles thresholds []*utils.TenantID // IDs of thresholds which need creation based on thresholdProfiles + lcrTntID []*utils.TenantID // IDs of thresholds which need creation based on thresholdProfiles revDests, revAliases, acntActionPlans map[string][]string thdsIndexers map[string]*ReqFilterIndexer // tenant, indexer sqpIndexers map[string]*ReqFilterIndexer // tenant, indexer resIndexers map[string]*ReqFilterIndexer // tenant, indexer + lcrIndexers map[string]*ReqFilterIndexer // tenant, indexer } func NewTpReader(db DataDB, lr LoadReader, tpid, timezone string) *TpReader { @@ -136,6 +139,7 @@ func (tpr *TpReader) Init() { tpr.resProfiles = make(map[utils.TenantID]*utils.TPResource) tpr.sqProfiles = make(map[utils.TenantID]*utils.TPStats) tpr.thProfiles = make(map[utils.TenantID]*utils.TPThreshold) + tpr.lcrProfiles = make(map[utils.TenantID]*utils.TPLCRProfile) tpr.filters = make(map[utils.TenantID]*utils.TPFilter) tpr.revDests = make(map[string][]string) tpr.revAliases = make(map[string][]string) @@ -143,6 +147,7 @@ func (tpr *TpReader) Init() { tpr.thdsIndexers = make(map[string]*ReqFilterIndexer) tpr.sqpIndexers = make(map[string]*ReqFilterIndexer) tpr.resIndexers = make(map[string]*ReqFilterIndexer) + tpr.lcrIndexers = make(map[string]*ReqFilterIndexer) } func (tpr *TpReader) LoadDestinationsFiltered(tag string) (bool, error) { @@ -1760,6 +1765,53 @@ func (tpr *TpReader) LoadFilters() error { return tpr.LoadFiltersFiltered("") } +func (tpr *TpReader) LoadLCRProfilesFiltered(tag string) (err error) { + rls, err := tpr.lr.GetTPLCRProfiles(tpr.tpid, tag) + if err != nil { + return err + } + mapRsPfls := make(map[utils.TenantID]*utils.TPLCRProfile) + for _, rl := range rls { + mapRsPfls[utils.TenantID{Tenant: rl.Tenant, ID: rl.ID}] = rl + } + tpr.lcrProfiles = mapRsPfls + for tntID, res := range mapRsPfls { + resIndxrKey := utils.LCRProfilesStringIndex + tntID.Tenant + if has, err := tpr.dm.HasData(utils.LCRProfilePrefix, tntID.TenantID()); err != nil { + return err + } else if !has { + tpr.lcrTntID = append(tpr.lcrTntID, &utils.TenantID{Tenant: tntID.Tenant, ID: tntID.ID}) + } + // index resource for filters + if _, has := tpr.lcrIndexers[tntID.Tenant]; !has { + if tpr.lcrIndexers[tntID.Tenant], err = NewReqFilterIndexer(tpr.dm, resIndxrKey); err != nil { + return + } + } + for _, fltrID := range res.FilterIDs { + tpFltr, has := tpr.filters[utils.TenantID{Tenant: tntID.Tenant, ID: fltrID}] + if !has { + var fltr *Filter + if fltr, err = tpr.dm.GetFilter(tntID.Tenant, fltrID, false, utils.NonTransactional); err != nil { + if err == utils.ErrNotFound { + err = fmt.Errorf("broken reference to filter: %+v for resoruce: %+v", fltrID, res) + } + return + } else { + tpFltr = FilterToTPFilter(fltr) + } + } else { + tpr.lcrIndexers[tntID.Tenant].IndexTPFilter(tpFltr, res.ID) + } + } + } + return nil +} + +func (tpr *TpReader) LoadLCRProfiles() error { + return tpr.LoadLCRProfilesFiltered("") +} + func (tpr *TpReader) LoadAll() (err error) { if err = tpr.LoadDestinations(); err != nil && err.Error() != utils.NotFoundCaps { return @@ -1821,6 +1873,9 @@ func (tpr *TpReader) LoadAll() (err error) { if err = tpr.LoadThresholds(); err != nil && err.Error() != utils.NotFoundCaps { return } + if err = tpr.LoadLCRProfiles(); err != nil && err.Error() != utils.NotFoundCaps { + return + } return nil } @@ -2155,6 +2210,23 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err log.Print("\t", thd.TenantID()) } } + + if verbose { + log.Print("LCRProfiles:") + } + for _, tpTH := range tpr.lcrProfiles { + th, err := APItoLCRProfile(tpTH, tpr.timezone) + if err != nil { + return err + } + if err = tpr.dm.SetLCRProfile(th); err != nil { + return err + } + if verbose { + log.Print("\t", th.TenantID()) + } + } + if verbose { log.Print("Timings:") } @@ -2226,6 +2298,18 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err log.Printf("Tenant: %s, keys %+v", tenant, fltrIdxer.ChangedKeys().Slice()) } } + + if verbose { + log.Print("Indexing LCRProfiles") + } + for tenant, fltrIdxer := range tpr.lcrIndexers { + if err := fltrIdxer.StoreIndexes(); err != nil { + return err + } + if verbose { + log.Printf("Tenant: %s, keys %+v", tenant, fltrIdxer.ChangedKeys().Slice()) + } + } } return } @@ -2287,7 +2371,7 @@ func (tpr *TpReader) ShowStatistics() { log.Print("LCR rules: ", len(tpr.lcrs)) // cdr stats log.Print("CDR stats: ", len(tpr.cdrStats)) - // resource limits + // resource profiles log.Print("ResourceProfiles: ", len(tpr.resProfiles)) // stats log.Print("Stats: ", len(tpr.sqProfiles)) @@ -2295,6 +2379,8 @@ func (tpr *TpReader) ShowStatistics() { log.Print("Thresholds: ", len(tpr.thProfiles)) // filters log.Print("Filters: ", len(tpr.filters)) + // LCR profiles + log.Print("LCRProfiles: ", len(tpr.lcrProfiles)) } // Returns the identities loaded for a specific category, useful for cache reloads @@ -2452,6 +2538,14 @@ func (tpr *TpReader) GetLoadedIds(categ string) ([]string, error) { i++ } return keys, nil + case utils.LCRProfilePrefix: + keys := make([]string, len(tpr.lcrProfiles)) + i := 0 + for k, _ := range tpr.lcrProfiles { + keys[i] = k.TenantID() + i++ + } + return keys, nil } return nil, errors.New("Unsupported load category") } diff --git a/utils/apitpdata.go b/utils/apitpdata.go index a53f77b9a..60a926e5b 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1354,3 +1354,17 @@ type TPRequestFilter struct { FieldName string // Name of the field providing us the Values to check (used in case of some ) Values []string // Filter definition } + +type TPLCRProfile struct { + TPid string + Tenant string + ID string + FilterIDs []string + ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires + Strategy string + StrategyParams []string + SupplierID string + RatingPlanIDs []string // RatingPlans used when computing price + StatIDs []string // StatProfiles queried in case of QoS based strategies + Weight float64 +} diff --git a/utils/consts.go b/utils/consts.go index a90d707b3..c61769707 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -64,6 +64,7 @@ var ( CacheThresholdProfiles: ThresholdProfilePrefix, CacheThresholds: ThresholdPrefix, CacheFilters: FilterPrefix, + CacheLCRProfiles: LCRProfilePrefix, } CachePrefixToInstance map[string]string // will be built on init ) @@ -114,6 +115,7 @@ const ( TBLTPFilters = "tp_filters" SMCostsTBL = "sm_costs" CDRsTBL = "cdrs" + TBLTPLCRProfiles = "tp_lcr" TBLVersions = "versions" TIMINGS_CSV = "Timings.csv" DESTINATIONS_CSV = "Destinations.csv" @@ -135,6 +137,7 @@ const ( StatsCsv = "Stats.csv" ThresholdsCsv = "Thresholds.csv" FiltersCsv = "Filters.csv" + LCRCsv = "Lcr.csv" ROUNDING_UP = "*up" ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down" @@ -265,6 +268,8 @@ const ( LOG_CDR = "cdr_" LOG_MEDIATED_CDR = "mcd_" StatQueueProfilePrefix = "sqp_" + LCRProfilePrefix = "lcp_" + LCRProfilesStringIndex = "lci_" ThresholdProfilePrefix = "thp_" StatQueuePrefix = "stq_" LOADINST_KEY = "load_history" @@ -462,6 +467,7 @@ const ( CacheThresholdProfiles = "threshold_profiles" CacheThresholds = "thresholds" CacheFilters = "filters" + CacheLCRProfiles = "lcr_profiles" AccountUpdate = "AccountUpdate" BalanceUpdate = "BalanceUpdate" StatUpdate = "StatUpdate" From 916b99712506296aea9ada078c8c905923c26c70 Mon Sep 17 00:00:00 2001 From: TeoV Date: Mon, 20 Nov 2017 17:20:08 +0200 Subject: [PATCH 64/75] LCRProfile(2) --- apier/v1/apier.go | 37 +++++++++- apier/v1/lcrs.go | 67 +++++++++++++++++++ apier/v1/smgenericv1_it_test.go | 2 +- apier/v2/apier.go | 4 +- cmd/cgr-engine/rater.go | 10 +-- cmd/cgr-loader/cgr-loader.go | 1 + cmd/cgr-tester/cgr-tester.go | 2 +- data/conf/cgrates/cgrates.json | 1 + data/conf/samples/tutmongo/cgrates.json | 1 + data/conf/samples/tutmysql/cgrates.json | 1 + .../mysql/create_tariffplan_tables.sql | 26 ++++++- .../postgres/create_tariffplan_tables.sql | 23 ++++++- data/tariffplans/tutorial/Filters.csv | 1 + engine/loader_csv_test.go | 38 ++++++++++- engine/loader_it_test.go | 18 +++++ engine/model_helpers.go | 16 ++--- engine/models.go | 4 +- engine/storage_mongo_stordb.go | 4 +- engine/storage_sql.go | 36 +++++++--- engine/storage_test.go | 2 +- engine/tp_reader.go | 6 +- engine/tpimporter_csv.go | 13 ++++ general_tests/acntacts_test.go | 5 +- general_tests/auth_test.go | 5 +- general_tests/costs1_test.go | 4 +- general_tests/datachrg1_test.go | 4 +- general_tests/ddazmbl1_test.go | 13 ++-- general_tests/ddazmbl2_test.go | 5 +- general_tests/ddazmbl3_test.go | 5 +- general_tests/smschrg1_test.go | 4 +- general_tests/tut_smgeneric_it_test.go | 2 +- general_tests/tutorial_it_test.go | 2 +- utils/apitpdata.go | 2 + utils/consts.go | 1 + 34 files changed, 304 insertions(+), 61 deletions(-) create mode 100644 apier/v1/lcrs.go diff --git a/apier/v1/apier.go b/apier/v1/apier.go index d04e670b4..b674dbcb1 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -1027,7 +1027,7 @@ func (self *ApierV1) LoadCache(args utils.AttrReloadCache, reply *string) (err e if args.FlushAll { cache.Flush() } - var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string + var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string if args.DestinationIDs == nil { dstIDs = nil } else { @@ -1128,8 +1128,13 @@ func (self *ApierV1) LoadCache(args utils.AttrReloadCache, reply *string) (err e } else { fltrIDs = *args.FilterIDs } + if args.LCRProfileIDs == nil { + lcrPrfIDs = nil + } else { + lcrPrfIDs = *args.LCRProfileIDs + } - if err := self.DataManager.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs); err != nil { + if err := self.DataManager.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK @@ -1276,6 +1281,13 @@ func (self *ApierV1) FlushCache(args utils.AttrReloadCache, reply *string) (err cache.RemKey(utils.FilterPrefix+key, true, utils.NonTransactional) } } + if args.LCRProfileIDs == nil { + cache.RemPrefixKey(utils.LCRProfilePrefix, true, utils.NonTransactional) + } else if len(*args.LCRProfileIDs) != 0 { + for _, key := range *args.LCRProfileIDs { + cache.RemKey(utils.LCRProfilePrefix+key, true, utils.NonTransactional) + } + } *reply = utils.OK return @@ -1302,6 +1314,7 @@ func (self *ApierV1) GetCacheStats(attrs utils.AttrCacheStats, reply *utils.Cach cs.Thresholds = cache.CountEntries(utils.ThresholdPrefix) cs.ThresholdProfiles = cache.CountEntries(utils.ThresholdProfilePrefix) cs.Filters = cache.CountEntries(utils.FilterPrefix) + cs.LCRProfiles = cache.CountEntries(utils.LCRProfilePrefix) if self.CdrStatsSrv != nil { var queueIds []string @@ -1691,6 +1704,25 @@ func (v1 *ApierV1) GetCacheKeys(args utils.ArgsCacheKeys, reply *utils.ArgsCache } } + if args.LCRProfileIDs != nil { + var ids []string + if len(*args.LCRProfileIDs) != 0 { + for _, id := range *args.LCRProfileIDs { + if _, hasIt := cache.Get(utils.LCRProfilePrefix + id); hasIt { + ids = append(ids, id) + } + } + } else { + for _, id := range cache.GetEntryKeys(utils.LCRProfilePrefix) { + ids = append(ids, id[len(utils.LCRProfilePrefix):]) + } + } + ids = args.Paginator.PaginateStringSlice(ids) + if len(ids) != 0 { + reply.LCRProfileIDs = &ids + } + } + return } @@ -1727,6 +1759,7 @@ func (self *ApierV1) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, path.Join(attrs.FolderPath, utils.StatsCsv), path.Join(attrs.FolderPath, utils.ThresholdsCsv), path.Join(attrs.FolderPath, utils.FiltersCsv), + path.Join(attrs.FolderPath, utils.LCRCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) diff --git a/apier/v1/lcrs.go b/apier/v1/lcrs.go new file mode 100644 index 000000000..280041407 --- /dev/null +++ b/apier/v1/lcrs.go @@ -0,0 +1,67 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package v1 + +import ( + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +// GetLCRProfile returns a LCDR configuration +func (apierV1 *ApierV1) GetLCRProfile(arg utils.TenantID, reply *engine.LCRProfile) error { + if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing + return utils.NewErrMandatoryIeMissing(missing...) + } + if rcfg, err := apierV1.DataManager.GetLCRProfile(arg.Tenant, arg.ID, false, utils.NonTransactional); err != nil { + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err + } else { + *reply = *rcfg + } + return nil +} + +//SetLCRProfile add a new LCR configuration +func (apierV1 *ApierV1) SetLCRProfile(res *engine.LCRProfile, reply *string) error { + if missing := utils.MissingStructFields(res, []string{"Tenant", "ID"}); len(missing) != 0 { + return utils.NewErrMandatoryIeMissing(missing...) + } + if err := apierV1.DataManager.SetLCRProfile(res); err != nil { + return utils.APIErrorHandler(err) + } + *reply = utils.OK + return nil +} + +//RemResourceProfile remove a specific resource configuration +func (apierV1 *ApierV1) RemLCRProfile(arg utils.TenantID, reply *string) error { + if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing + return utils.NewErrMandatoryIeMissing(missing...) + } + if err := apierV1.DataManager.RemoveLCRProfile(arg.Tenant, arg.ID, utils.NonTransactional); err != nil { + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err + } + *reply = utils.OK + return nil +} diff --git a/apier/v1/smgenericv1_it_test.go b/apier/v1/smgenericv1_it_test.go index 52b58d0fa..5be38db35 100644 --- a/apier/v1/smgenericv1_it_test.go +++ b/apier/v1/smgenericv1_it_test.go @@ -103,7 +103,7 @@ func TestSMGV1CacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := smgV1Rpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) diff --git a/apier/v2/apier.go b/apier/v2/apier.go index 754adb1cf..63a48df0d 100644 --- a/apier/v2/apier.go +++ b/apier/v2/apier.go @@ -144,6 +144,7 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, path.Join(attrs.FolderPath, utils.StatsCsv), path.Join(attrs.FolderPath, utils.ThresholdsCsv), path.Join(attrs.FolderPath, utils.FiltersCsv), + path.Join(attrs.FolderPath, utils.LCRCsv), ), "", self.Config.DefaultTimezone) if err := loader.LoadAll(); err != nil { return utils.NewErrServerError(err) @@ -184,7 +185,8 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder, utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, - utils.FilterPrefix} { + utils.FilterPrefix, + utils.LCRProfilePrefix} { loadedIDs, _ := loader.GetLoadedIds(prfx) if err := self.DataManager.CacheDataFromDB(prfx, loadedIDs, true); err != nil { return utils.NewErrServerError(err) diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index 2c1abeafe..653193c50 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -43,9 +43,8 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) - var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, - lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs []string - if cCfg, has := cacheCfg[utils.CacheDestinations]; !has || !cCfg.Precache { + var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string + if cCfg, has := ccacheCfg[utils.CacheDestinations]; !has || !cCfg.Precache { dstIDs = make([]string, 0) // Don't cache any } if cCfg, has := cacheCfg[utils.CacheReverseDestinations]; !has || !cCfg.Precache { @@ -105,9 +104,12 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC if cCfg, has := cacheCfg[utils.CacheFilters]; !has || !cCfg.Precache { fltrIDs = make([]string, 0) } + if cCfg, has := cfg.CacheConfig[utils.CacheLCRProfiles]; !has || !cCfg.Precache { + lcrPrfIDs = make([]string, 0) + } // ToDo: Add here timings - if err := dm.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs); err != nil { + if err := dm.LoadDataDBCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs); err != nil { utils.Logger.Crit(fmt.Sprintf(" Cache rating error: %s", err.Error())) exitChan <- true return diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index f4197cba8..d450c30d8 100755 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -149,6 +149,7 @@ func main() { path.Join(*dataPath, utils.StatsCsv), path.Join(*dataPath, utils.ThresholdsCsv), path.Join(*dataPath, utils.FiltersCsv), + path.Join(*dataPath, utils.LCRCsv), ) } diff --git a/cmd/cgr-tester/cgr-tester.go b/cmd/cgr-tester/cgr-tester.go index 7ba39f943..37cb96da0 100644 --- a/cmd/cgr-tester/cgr-tester.go +++ b/cmd/cgr-tester/cgr-tester.go @@ -68,7 +68,7 @@ func durInternalRater(cd *engine.CallDescriptor) (time.Duration, error) { } defer dm.DataDB().Close() engine.SetDataStorage(dm) - if err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil { + if err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil { return nilDuration, fmt.Errorf("Cache rating error: %s", err.Error()) } log.Printf("Runnning %d cycles...", *runs) diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index a5e3f3d95..0621035a3 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -46,6 +46,7 @@ // "derived_chargers": {"limit": 10000, "ttl":"0s", "precache": false}, // control derived charging rule caching // "resource_limits": {"limit": 10000, "ttl":"0s", "precache": false}, // control resource limits caching // "timings": {"limit": 10000, "ttl":"0s", "precache": false}, // control timings caching +// "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, // control lcr_rofiles caching // }, diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json index 640c89286..cc6f6d257 100644 --- a/data/conf/samples/tutmongo/cgrates.json +++ b/data/conf/samples/tutmongo/cgrates.json @@ -49,6 +49,7 @@ "thresholds": {"limit": 10000, "ttl":"0s", "precache": true}, "threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, "filters": {"limit": 10000, "ttl":"0s", "precache": true}, + "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, }, diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json index 3468f3e06..6b5be1e22 100644 --- a/data/conf/samples/tutmysql/cgrates.json +++ b/data/conf/samples/tutmysql/cgrates.json @@ -42,6 +42,7 @@ "thresholds": {"limit": 10000, "ttl":"0s", "precache": true}, "threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, "filters": {"limit": 10000, "ttl":"0s", "precache": true}, + "lcr_profiles": {"limit": 10000, "ttl":"0s", "precache": true}, }, diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 36553caa1..042fc24d9 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -487,6 +487,30 @@ CREATE TABLE tp_filters ( UNIQUE KEY `unique_tp_filters` (`tpid`,`tenant`, `id`, `filter_type`, `filter_field_name`) ); +-- +-- Table structure for table `tp_lcr` +-- + +DROP TABLE IF EXISTS tp_lcrs; +CREATE TABLE tp_lcrs ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `tpid` varchar(64) NOT NULL, + `tenant` varchar(64) NOT NULL, + `id` varchar(64) NOT NULL, + `filter_ids` varchar(64) NOT NULL, + `activation_interval` varchar(64) NOT NULL, + `strategy` varchar(32) NOT NULL, + `strategy_params` varchar(64) NOT NULL, + `supplier_id` varchar(32) NOT NULL, + `ratingplan_ids` varchar(64) NOT NULL, + `stat_ids` varchar(64) NOT NULL, + `weight` decimal(8,2) NOT NULL, + `created_at` TIMESTAMP, + PRIMARY KEY (`pk`), + KEY `tpid` (`tpid`), + UNIQUE KEY `unique_tp_lcr` (`tpid`,`tenant`, `id`,`filter_ids` ) +); + -- -- Table structure for table `versions` -- @@ -497,5 +521,5 @@ CREATE TABLE versions ( `item` varchar(64) NOT NULL, `version` int(11) NOT NULL, PRIMARY KEY (`id`), - UNIQUE KEY `item` (`item`) + UNIQUE KEY `id_item` (`id`,`item`) ); diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 749ff012c..2a99637ae 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -480,7 +480,28 @@ CREATE TABLE tp_filters ( CREATE INDEX tp_filters_idx ON tp_filters (tpid); CREATE INDEX tp_filters_unique ON tp_filters ("tpid","tenant", "id", "filter_type", "filter_field_name"); + -- + -- Table structure for table `tp_resources` + -- + DROP TABLE IF EXISTS tp_lcrs; + CREATE TABLE tp_lcrs ( + "pk" SERIAL PRIMARY KEY, + "tpid" varchar(64) NOT NULL, + "tenant"varchar(64) NOT NULL, + "id" varchar(64) NOT NULL, + "filter_ids" varchar(64) NOT NULL, + "activation_interval" varchar(64) NOT NULL, + "strategy" varchar(32) NOT NULL, + "strategy_params" varchar(64) NOT NULL, + "supplier_id" varchar(32) NOT NULL, + "ratingplan_ids" varchar(64) NOT NULL, + "stat_ids" varchar(64) NOT NULL, + "weight" decimal(8,2) NOT NULL, + "created_at" TIMESTAMP WITH TIME ZONE + ); + CREATE INDEX tp_lcrs_idx ON tp_lcrs (tpid); + CREATE INDEX tp_lcrs_unique ON tp_lcrs ("tpid", "tenant", "id", "filter_ids"); -- -- Table structure for table `versions` @@ -491,5 +512,5 @@ CREATE TABLE versions ( "id" SERIAL PRIMARY KEY, "item" varchar(64) NOT NULL, "version" INTEGER NOT NULL, - UNIQUE (item) + UNIQUE ("id","item") ); diff --git a/data/tariffplans/tutorial/Filters.csv b/data/tariffplans/tutorial/Filters.csv index 4c1f4ffa0..180334d4a 100644 --- a/data/tariffplans/tutorial/Filters.csv +++ b/data/tariffplans/tutorial/Filters.csv @@ -3,6 +3,7 @@ cgrates.org,FLTR_1,*string,Account,1001;1002,2014-07-29T15:00:00Z cgrates.org,FLTR_1,*string_prefix,Destination,10;20, cgrates.org,FLTR_1,*rsr_fields,,Subject(~^1.*1$);Destination(1002), cgrates.org,FLTR_ACNT_1007,*string,Account,1007,2014-07-29T15:00:00Z +cgrates.org,FLTR_ACNT_dan,*string,Account,dan,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_DE,*destinations,Destination,DST_DE,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_NL,*destinations,Destination,DST_NL,2014-07-29T15:00:00Z cgrates.org,FLTR_ACNT_BALANCE_1,*string,Account,1001;1002,2014-07-29T15:00:00Z diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 7469a892e..9b525e6e2 100755 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -289,6 +289,10 @@ cgrates.org,FLTR_1,*rsr_fields,,Subject(~^1.*1$);Destination(1002), cgrates.org,FLTR_ACNT_dan,*string,Account,dan,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_DE,*destinations,Destination,DST_DE,2014-07-29T15:00:00Z cgrates.org,FLTR_DST_NL,*destinations,Destination,DST_NL,2014-07-29T15:00:00Z +` + lcrProfiles = ` +#Tenant,ID,FilterIDs,ActivationInterval,Strategy,StrategyParams,SupplierID,RatingPlanIDs,StatIDs,Weight +cgrates.org,LCR_1,FLTR_ACNT_dan;FLTR_DST_DE,2014-07-29T15:00:00Z,*lowest_cost,,supplier1,RPL_1,,20 ` ) @@ -296,7 +300,7 @@ var csvr *TpReader func init() { csvr = NewTpReader(dm.dataDB, NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resProfiles, stats, thresholds, filters), testTPID, "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resProfiles, stats, thresholds, filters, lcrProfiles), testTPID, "") if err := csvr.LoadDestinations(); err != nil { log.Print("error in LoadDestinations:", err) @@ -358,9 +362,12 @@ func init() { if err := csvr.LoadThresholds(); err != nil { log.Print("error in LoadThresholds:", err) } + if err := csvr.LoadLCRProfiles(); err != nil { + log.Print("error in LoadThresholds:", err) + } csvr.WriteToDatabase(false, false, false) cache.Flush() - dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) } func TestLoadDestinations(t *testing.T) { @@ -1439,7 +1446,6 @@ func TestLoadResourceProfiles(t *testing.T) { } else if !reflect.DeepEqual(eResProfiles[resKey], csvr.resProfiles[resKey]) { t.Errorf("Expecting: %+v, received: %+v", eResProfiles[resKey], csvr.resProfiles[resKey]) } - } func TestLoadStatProfiles(t *testing.T) { @@ -1612,6 +1618,32 @@ func TestLoadFilters(t *testing.T) { } } +func TestLoadLCRProfiles(t *testing.T) { + eLCRprofiles := map[utils.TenantID]*utils.TPLCRProfile{ + utils.TenantID{Tenant: "cgrates.org", ID: "LCR_1"}: &utils.TPLCRProfile{ + TPid: testTPID, + Tenant: "cgrates.org", + ID: "LCR_1", + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-29T15:00:00Z", + }, + Strategy: "*lowest_cost", + StrategyParams: nil, + SupplierID: "supplier1", + RatingPlanIDs: []string{"RPL_1"}, + StatIDs: nil, + Weight: 20, + }, + } + resKey := utils.TenantID{Tenant: "cgrates.org", ID: "LCR_1"} + if len(csvr.lcrProfiles) != len(eLCRprofiles) { + t.Errorf("Failed to load LCRProfiles: %s", utils.ToIJSON(csvr.lcrProfiles)) + } else if !reflect.DeepEqual(eLCRprofiles[resKey], csvr.lcrProfiles[resKey]) { + t.Errorf("Expecting: %+v, received: %+v", eLCRprofiles[resKey], csvr.lcrProfiles[resKey]) + } +} + func TestLoadResource(t *testing.T) { eResources := []*utils.TenantID{ &utils.TenantID{ diff --git a/engine/loader_it_test.go b/engine/loader_it_test.go index ad6c89f55..f66a8bb6b 100755 --- a/engine/loader_it_test.go +++ b/engine/loader_it_test.go @@ -108,6 +108,7 @@ func TestLoaderITLoadFromCSV(t *testing.T) { path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.StatsCsv), path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.ThresholdsCsv), path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.FiltersCsv), + path.Join(*dataDir, "tariffplans", *tpCsvScenario, utils.LCRCsv), ), "", "") if err = loader.LoadDestinations(); err != nil { @@ -164,6 +165,9 @@ func TestLoaderITLoadFromCSV(t *testing.T) { if err = loader.LoadThresholds(); err != nil { t.Error("Failed loading thresholds: ", err.Error()) } + if err = loader.LoadLCRProfiles(); err != nil { + t.Error("Failed loading lcr profiles: ", err.Error()) + } if err := loader.WriteToDatabase(true, false, false); err != nil { t.Error("Could not write data into dataDb: ", err.Error()) } @@ -353,6 +357,20 @@ func TestLoaderITWriteToDatabase(t *testing.T) { t.Errorf("Expecting: %v, received: %v", sts, rcv) } } + + for tenatid, th := range loader.lcrProfiles { + rcv, err := loader.dm.GetLCRProfile(tenatid.Tenant, tenatid.ID, true, utils.NonTransactional) + if err != nil { + t.Errorf("Failed GetLCRProfile, tenant: %s, id: %s, error: %s ", th.Tenant, th.ID, err.Error()) + } + sts, err := APItoLCRProfile(th, "UTC") + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(sts, rcv) { + t.Errorf("Expecting: %v, received: %v", sts, rcv) + } + } } // Imports data from csv files in tpScenario to storDb diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 57fbbd0a8..5f016f0b4 100755 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -2419,9 +2419,9 @@ func FilterToTPFilter(f *Filter) (tpFltr *utils.TPFilter) { return } -type TpLCRProfiles []*TpLCRProfile +type TpLCRs []*TpLCR -func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { +func (tps TpLCRs) AsTPLCRProfile() (result []*utils.TPLCRProfile) { mst := make(map[string]*utils.TPLCRProfile) for _, tp := range tps { th, found := mst[tp.ID] @@ -2440,8 +2440,8 @@ func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { th.StrategyParams = append(th.StrategyParams, strategyParam) } } - if tp.RatingPlanIDs != "" { - ratingPlansIDsSplit := strings.Split(tp.RatingPlanIDs, utils.INFIELD_SEP) + if tp.RatingplanIDs != "" { + ratingPlansIDsSplit := strings.Split(tp.RatingplanIDs, utils.INFIELD_SEP) for _, ratingPlanID := range ratingPlansIDsSplit { th.RatingPlanIDs = append(th.RatingPlanIDs, ratingPlanID) } @@ -2483,10 +2483,10 @@ func (tps TpLCRProfiles) AsTPLCRProfile() (result []*utils.TPLCRProfile) { return } -func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRProfiles) { +func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRs) { if st != nil { for i, fltr := range st.FilterIDs { - mdl := &TpLCRProfile{ + mdl := &TpLCR{ Tenant: st.Tenant, Tpid: st.TPid, ID: st.ID, @@ -2503,9 +2503,9 @@ func APItoModelTPLCRProfile(st *utils.TPLCRProfile) (mdls TpLCRProfiles) { } for i, val := range st.RatingPlanIDs { if i != 0 { - mdl.RatingPlanIDs += utils.INFIELD_SEP + mdl.RatingplanIDs += utils.INFIELD_SEP } - mdl.RatingPlanIDs += val + mdl.RatingplanIDs += val } for i, val := range st.StatIDs { if i != 0 { diff --git a/engine/models.go b/engine/models.go index e218c3dac..2f1379da6 100755 --- a/engine/models.go +++ b/engine/models.go @@ -520,7 +520,7 @@ func (t TBLVersion) TableName() string { return utils.TBLVersions } -type TpLCRProfile struct { +type TpLCR struct { PK uint `gorm:"primary_key"` Tpid string Tenant string `index:"0" re:""` @@ -530,7 +530,7 @@ type TpLCRProfile struct { Strategy string `index:"4" re:""` StrategyParams string `index:"5" re:""` SupplierID string `index:"6" re:""` - RatingPlanIDs string `index:"7" re:""` + RatingplanIDs string `index:"7" re:""` StatIDs string `index:"8" re:""` Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 866e6efc2..808aa2d2e 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1235,7 +1235,7 @@ func (ms *MongoStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile filter["id"] = id } var results []*utils.TPLCRProfile - session, col := ms.conn(utils.TBLTPLCRProfiles) + session, col := ms.conn(utils.TBLTPLcr) defer session.Close() err := col.Find(filter).All(&results) if len(results) == 0 { @@ -1248,7 +1248,7 @@ func (ms *MongoStorage) SetTPLCRProfiles(tpTHs []*utils.TPLCRProfile) (err error if len(tpTHs) == 0 { return } - session, col := ms.conn(utils.TBLTPLCRProfiles) + session, col := ms.conn(utils.TBLTPLcr) defer session.Close() tx := col.Bulk() for _, tp := range tpTHs { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 83d0a1aab..7cf9f7db1 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -107,7 +107,8 @@ func (self *SQLStorage) IsDBEmpty() (resp bool, err error) { utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, utils.TBLTPDerivedChargers, utils.TBLTPUsers, utils.TBLTPAliases, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPThresholds, - utils.TBLTPFilters, utils.SMCostsTBL, utils.CDRsTBL, utils.TBLTPActionPlans, utils.TBLVersions, + utils.TBLTPFilters, utils.SMCostsTBL, utils.CDRsTBL, utils.TBLTPActionPlans, + utils.TBLVersions, utils.TBLTPLcr, } for _, tbl := range tbls { if self.db.HasTable(tbl) { @@ -126,7 +127,7 @@ func (self *SQLStorage) GetTpIds(colName string) ([]string, error) { qryStr := fmt.Sprintf(" (SELECT tpid FROM %s)", colName) if colName == "" { qryStr = fmt.Sprintf( - "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", + "(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, @@ -146,7 +147,8 @@ func (self *SQLStorage) GetTpIds(colName string) ([]string, error) { utils.TBLTPStats, utils.TBLTPThresholds, utils.TBLTPFilters, - utils.TBLTPActionPlans) + utils.TBLTPActionPlans, + utils.TBLTPLcr) } rows, err = self.Db.Query(qryStr) if err != nil { @@ -234,7 +236,7 @@ func (self *SQLStorage) RemTpData(table, tpid string, args map[string]string) er if len(table) == 0 { // Remove tpid out of all tables for _, tblName := range []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans, utils.TBLTPRateProfiles, utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, - utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPFilters} { + utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPFilters, utils.TBLTPLcr} { if err := tx.Table(tblName).Where("tpid = ?", tpid).Delete(nil).Error; err != nil { tx.Rollback() return err @@ -689,18 +691,18 @@ func (self *SQLStorage) SetTPFilters(ths []*utils.TPFilter) error { return nil } -func (self *SQLStorage) SetTPLCRProfile(ths []*utils.TPLCRProfile) error { - if len(ths) == 0 { +func (self *SQLStorage) SetTPLCRProfiles(sts []*utils.TPLCRProfile) error { + if len(sts) == 0 { return nil } tx := self.db.Begin() - for _, th := range ths { + for _, stq := range sts { // Remove previous - if err := tx.Where(&TpLCRProfile{Tpid: th.TPid, ID: th.ID}).Delete(TpLCRProfile{}).Error; err != nil { + if err := tx.Where(&TpLCR{Tpid: stq.TPid, ID: stq.ID}).Delete(TpLCR{}).Error; err != nil { tx.Rollback() return err } - for _, mst := range APItoModelTPLCRProfile(th) { + for _, mst := range APItoModelTPLCRProfile(stq) { if err := tx.Save(&mst).Error; err != nil { tx.Rollback() return err @@ -1553,6 +1555,22 @@ func (self *SQLStorage) GetTPFilters(tpid, id string) ([]*utils.TPFilter, error) return aths, nil } +func (self *SQLStorage) GetTPLCRProfiles(tpid, id string) ([]*utils.TPLCRProfile, error) { + var rls TpLCRs + q := self.db.Where("tpid = ?", tpid) + if len(id) != 0 { + q = q.Where("id = ?", id) + } + if err := q.Find(&rls).Error; err != nil { + return nil, err + } + arls := rls.AsTPLCRProfile() + if len(arls) == 0 { + return arls, utils.ErrNotFound + } + return arls, nil +} + // GetVersions returns slice of all versions or a specific version if tag is specified func (self *SQLStorage) GetVersions(itm string) (vrs Versions, err error) { q := self.db.Model(&TBLVersion{}) diff --git a/engine/storage_test.go b/engine/storage_test.go index 000accc23..9f455e4c6 100644 --- a/engine/storage_test.go +++ b/engine/storage_test.go @@ -102,7 +102,7 @@ func TestStorageCacheRefresh(t *testing.T) { dm.DataDB().GetDestination("T11", false, utils.NonTransactional) dm.DataDB().SetDestination(&Destination{"T11", []string{"1"}}, utils.NonTransactional) t.Log("Test cache refresh") - err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + err := dm.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if err != nil { t.Error("Error cache rating: ", err) } diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 14eb4585c..5453e43fc 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -1782,7 +1782,7 @@ func (tpr *TpReader) LoadLCRProfilesFiltered(tag string) (err error) { } else if !has { tpr.lcrTntID = append(tpr.lcrTntID, &utils.TenantID{Tenant: tntID.Tenant, ID: tntID.ID}) } - // index resource for filters + // index lcr profile for filters if _, has := tpr.lcrIndexers[tntID.Tenant]; !has { if tpr.lcrIndexers[tntID.Tenant], err = NewReqFilterIndexer(tpr.dm, resIndxrKey); err != nil { return @@ -2212,7 +2212,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err } if verbose { - log.Print("LCRProfiles:") + log.Print("LCR Profiles:") } for _, tpTH := range tpr.lcrProfiles { th, err := APItoLCRProfile(tpTH, tpr.timezone) @@ -2300,7 +2300,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err } if verbose { - log.Print("Indexing LCRProfiles") + log.Print("Indexing LCR Profiles") } for tenant, fltrIdxer := range tpr.lcrIndexers { if err := fltrIdxer.StoreIndexes(); err != nil { diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index 01332eb22..733ccd30e 100755 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -61,6 +61,7 @@ var fileHandlers = map[string]func(*TPCSVImporter, string) error{ utils.StatsCsv: (*TPCSVImporter).importStats, utils.ThresholdsCsv: (*TPCSVImporter).importThresholds, utils.FiltersCsv: (*TPCSVImporter).importFilters, + utils.LCRCsv: (*TPCSVImporter).importLCR, } func (self *TPCSVImporter) Run() error { @@ -85,6 +86,7 @@ func (self *TPCSVImporter) Run() error { path.Join(self.DirPath, utils.StatsCsv), path.Join(self.DirPath, utils.ThresholdsCsv), path.Join(self.DirPath, utils.FiltersCsv), + path.Join(self.DirPath, utils.LCRCsv), ) files, _ := ioutil.ReadDir(self.DirPath) for _, f := range files { @@ -397,3 +399,14 @@ func (self *TPCSVImporter) importFilters(fn string) error { } return self.StorDb.SetTPFilters(sts) } + +func (self *TPCSVImporter) importLCR(fn string) error { + if self.Verbose { + log.Printf("Processing file: <%s> ", fn) + } + rls, err := self.csvr.GetTPLCRProfiles(self.TPid, "") + if err != nil { + return err + } + return self.StorDb.SetTPLCRProfiles(rls) +} diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index a1d84cdf1..eaa6ce72f 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -57,15 +57,16 @@ ENABLE_ACNT,*enable_account,,,,,,,,,,,,,,false,false,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dbAcntActs.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadAll(); err != nil { t.Fatal(err) } csvr.WriteToDatabase(false, false, false) cache.Flush() - dbAcntActs.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dbAcntActs.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) expectAcnt := &engine.Account{ID: "cgrates.org:1"} if acnt, err := dbAcntActs.DataDB().GetAccount("cgrates.org:1"); err != nil { diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index f856b61f4..c73de55f7 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -64,8 +64,9 @@ RP_ANY,DR_ANY_1CNT,*any,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dbAuth.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadAll(); err != nil { t.Fatal(err) } @@ -77,7 +78,7 @@ RP_ANY,DR_ANY_1CNT,*any,10` } cache.Flush() - dbAuth.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dbAuth.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/costs1_test.go b/general_tests/costs1_test.go index 3990197d3..9c2926401 100644 --- a/general_tests/costs1_test.go +++ b/general_tests/costs1_test.go @@ -52,7 +52,7 @@ RP_SMS1,DR_SMS_1,ALWAYS,10` *out,cgrates.org,data,*any,2012-01-01T00:00:00Z,RP_DATA1,, *out,cgrates.org,sms,*any,2012-01-01T00:00:00Z,RP_SMS1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', dests, timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) @@ -74,7 +74,7 @@ RP_SMS1,DR_SMS_1,ALWAYS,10` } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 3 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/datachrg1_test.go b/general_tests/datachrg1_test.go index 75f32caa3..1761bc983 100644 --- a/general_tests/datachrg1_test.go +++ b/general_tests/datachrg1_test.go @@ -43,7 +43,7 @@ DR_DATA_2,*any,RT_DATA_1c,*up,4,0,` RP_DATA1,DR_DATA_2,TM2,10` ratingProfiles := `*out,cgrates.org,data,*any,2012-01-01T00:00:00Z,RP_DATA1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', "", timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ RP_DATA1,DR_DATA_2,TM2,10` } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 1 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index 096139b6f..f67bee41c 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -64,12 +64,9 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` - csvr := engine.NewTpReader(dataDB.DataDB(), - engine.NewStringCSVStorage(',', destinations, timings, rates, - destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, - accountActions, derivedCharges, cdrStats, users, aliases, - resLimits, stats, thresholds, filters), "", "") + lcrprofiles := `` + csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -116,8 +113,12 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() +<<<<<<< HEAD /* dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) +======= + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) +>>>>>>> LCRProfile(2) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/ddazmbl2_test.go b/general_tests/ddazmbl2_test.go index 24fa3d005..5362da005 100644 --- a/general_tests/ddazmbl2_test.go +++ b/general_tests/ddazmbl2_test.go @@ -64,8 +64,9 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dataDB2.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -112,7 +113,7 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() - dataDB2.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB2.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/ddazmbl3_test.go b/general_tests/ddazmbl3_test.go index 39f0fe81b..f4aae38b7 100644 --- a/general_tests/ddazmbl3_test.go +++ b/general_tests/ddazmbl3_test.go @@ -62,8 +62,9 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` stats := `` thresholds := `` filters := `` + lcrprofiles := `` csvr := engine.NewTpReader(dataDB3.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters), "", "") + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -110,7 +111,7 @@ RP_UK,DR_UK_Mobile_BIG5,ALWAYS,10` t.Error("No account saved") } cache.Flush() - dataDB3.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB3.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) diff --git a/general_tests/smschrg1_test.go b/general_tests/smschrg1_test.go index cadc357f5..c5e479109 100644 --- a/general_tests/smschrg1_test.go +++ b/general_tests/smschrg1_test.go @@ -41,7 +41,7 @@ func TestSMSLoadCsvTpSmsChrg1(t *testing.T) { ratingPlans := `RP_SMS1,DR_SMS_1,ALWAYS,10` ratingProfiles := `*out,cgrates.org,sms,*any,2012-01-01T00:00:00Z,RP_SMS1,,` csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', "", timings, rates, destinationRates, ratingPlans, ratingProfiles, - "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") + "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""), "", "") if err := csvr.LoadTimings(); err != nil { t.Fatal(err) } @@ -59,7 +59,7 @@ func TestSMSLoadCsvTpSmsChrg1(t *testing.T) { } csvr.WriteToDatabase(false, false, false) cache.Flush() - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) if cachedRPlans := cache.CountEntries(utils.RATING_PLAN_PREFIX); cachedRPlans != 1 { t.Error("Wrong number of cached rating plans found", cachedRPlans) diff --git a/general_tests/tut_smgeneric_it_test.go b/general_tests/tut_smgeneric_it_test.go index e2aaf044f..809e01220 100644 --- a/general_tests/tut_smgeneric_it_test.go +++ b/general_tests/tut_smgeneric_it_test.go @@ -101,7 +101,7 @@ func TestTutSMGCacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := tutSMGRpc.Call("ApierV2.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV2.GetCacheStats: ", err.Error()) diff --git a/general_tests/tutorial_it_test.go b/general_tests/tutorial_it_test.go index c31553d2d..8881fd4e7 100644 --- a/general_tests/tutorial_it_test.go +++ b/general_tests/tutorial_it_test.go @@ -105,7 +105,7 @@ func TestTutITCacheStats(t *testing.T) { expectedStats := &utils.CacheStats{Destinations: 5, ReverseDestinations: 7, RatingPlans: 4, RatingProfiles: 10, Actions: 9, ActionPlans: 4, AccountActionPlans: 5, SharedGroups: 1, DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, Aliases: 1, ReverseAliases: 2, ResourceProfiles: 3, Resources: 3, StatQueues: 1, - StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 15} + StatQueueProfiles: 1, Thresholds: 7, ThresholdProfiles: 7, Filters: 16} var args utils.AttrCacheStats if err := tutLocalRpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil { t.Error("Got error on ApierV1.GetCacheStats: ", err.Error()) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 60a926e5b..48e5d36ef 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -675,6 +675,7 @@ type ArgsCache struct { ThresholdIDs *[]string ThresholdProfileIDs *[]string FilterIDs *[]string + LCRProfileIDs *[]string } // Data used to do remote cache reloads via api @@ -716,6 +717,7 @@ type CacheStats struct { Thresholds int ThresholdProfiles int Filters int + LCRProfiles int // LCRProfiles } type AttrExpFileCdrs struct { diff --git a/utils/consts.go b/utils/consts.go index c61769707..9041fd28b 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -116,6 +116,7 @@ const ( SMCostsTBL = "sm_costs" CDRsTBL = "cdrs" TBLTPLCRProfiles = "tp_lcr" + TBLTPLcr = "tp_lcrs" TBLVersions = "versions" TIMINGS_CSV = "Timings.csv" DESTINATIONS_CSV = "Destinations.csv" From 99911a077ed527d78e2d99214db9a646ba971e46 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 30 Oct 2017 18:18:37 +0100 Subject: [PATCH 65/75] Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update --- engine/cdr.go | 35 ++++++++++++++++++++++++ engine/cdr_test.go | 22 +++++++++++++++ engine/cgrcdr_test.go | 4 +++ engine/models.go | 58 ++++++++++++++++++++++++++++++++++++++++ engine/responder_test.go | 37 +++++++++++++++++++++++++ engine/storage_sql.go | 35 ++++++++++++++++++++++++ engine/version.go | 50 +++++++++++++++++----------------- 7 files changed, 216 insertions(+), 25 deletions(-) diff --git a/engine/cdr.go b/engine/cdr.go index 6c33eef33..5f6b246d8 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -175,7 +175,11 @@ func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { case utils.ANSWER_TIME: return rsrFld.ParseValue(cdr.AnswerTime.Format(time.RFC3339)) case utils.USAGE: +<<<<<<< HEAD return cdr.Usage.String() +======= + return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update case utils.MEDI_RUNID: return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: @@ -380,7 +384,11 @@ 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) +<<<<<<< HEAD } else if frkStorCdr.Usage, err = utils.ParseDurationWithNanosecs(durStr); err != nil { +======= + } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } ratedStr := cdr.FieldAsString(ratedFld) @@ -425,7 +433,11 @@ func (cdr *CDR) AsExternalCDR() *ExternalCDR { Destination: cdr.Destination, SetupTime: cdr.SetupTime.Format(time.RFC3339), AnswerTime: cdr.AnswerTime.Format(time.RFC3339), +<<<<<<< HEAD Usage: usageStr, +======= + Usage: cdr.FormatUsage(utils.SECONDS), +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: cdr.ExtraFields, CostSource: cdr.CostSource, Cost: cdr.Cost, @@ -554,7 +566,11 @@ func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { } else { durVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } +<<<<<<< HEAD return utils.ParseDurationWithNanosecs(durVal) +======= + return utils.ParseDurationWithSecs(durVal) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { @@ -768,7 +784,11 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck // AsCDRsTBL converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { cdrSql = new(CDRsql) +<<<<<<< HEAD cdrSql.Cgrid = cdr.CGRID +======= + cdrSql.CGRID = cdr.CGRID +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdrSql.RunID = cdr.RunID cdrSql.OriginHost = cdr.OriginHost cdrSql.Source = cdr.Source @@ -795,12 +815,19 @@ func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { // NewCDRFromSQL converts the CDRsql into CDR func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr = new(CDR) +<<<<<<< HEAD cdr.CGRID = cdrSql.Cgrid +======= + cdr.CGRID = cdrSql.CGRID +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.RunID = cdrSql.RunID cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source cdr.OriginID = cdrSql.OriginID +<<<<<<< HEAD cdr.OrderID = cdrSql.ID +======= +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.ToR = cdrSql.TOR cdr.RequestType = cdrSql.RequestType cdr.Tenant = cdrSql.Tenant @@ -811,6 +838,10 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr.SetupTime = cdrSql.SetupTime cdr.AnswerTime = cdrSql.AnswerTime cdr.Usage = time.Duration(cdrSql.Usage) +<<<<<<< HEAD +======= + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.CostSource = cdrSql.CostSource cdr.Cost = cdrSql.Cost cdr.ExtraInfo = cdrSql.ExtraInfo @@ -820,7 +851,11 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { } } if cdrSql.CostDetails != "" { +<<<<<<< HEAD if err = json.Unmarshal([]byte(cdrSql.CostDetails), &cdr.CostDetails); err != nil { +======= + if err = json.Unmarshal([]byte(cdrSql.CostDetails), cdr.CostDetails); err != nil { +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } } diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 94a4b2451..858d1f750 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -98,7 +98,11 @@ 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) || +<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s" || +======= + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" || +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update 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 +122,11 @@ 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), +<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s", +======= + cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10", +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update 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"], @@ -395,7 +403,11 @@ func TestCDRAsExternalCDR(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), +<<<<<<< HEAD RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10 * time.Second), Cost: 1.01, +======= + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} expectOutCdr := &ExternalCDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -403,7 +415,11 @@ func TestCDRAsExternalCDR(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, +<<<<<<< HEAD Usage: "10s", Cost: 1.01, CostDetails: "null", +======= + Usage: "0.00000001", Cost: 1.01, CostDetails: "null", +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) @@ -497,9 +513,15 @@ 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", +<<<<<<< HEAD Usage: "10", } eCD := &CallDescriptor{CgrID: "c4630df20b2a0c5b11311e4b5a8c3178cf314344", TOR: req.ToR, +======= + Usage: "0.00000001", + } + eCD := &CallDescriptor{CgrID: "48ca1a2eb82b028fbfc809e36a585061a775ffc3", TOR: req.ToR, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update Direction: utils.OUT, Tenant: req.Tenant, Category: req.Category, Account: req.Account, Subject: req.Subject, Destination: req.Destination, diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index 71ad57a00..106cbc3ba 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -38,7 +38,11 @@ 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", +<<<<<<< HEAD utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} +======= + utils.USAGE: "10", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], diff --git a/engine/models.go b/engine/models.go index 2f1379da6..230de04b5 100755 --- a/engine/models.go +++ b/engine/models.go @@ -535,3 +535,61 @@ type TpLCR struct { Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time } + +type CDRsql struct { + ID int64 + CGRID string + RunID string + OriginHost string + Source string + OriginID string + TOR string + RequestType string + Tenant string + Category string + Account string + Subject string + Destination string + SetupTime time.Time + AnswerTime time.Time + Usage int64 + ExtraFields string + CostSource string + Cost float64 + CostDetails string + ExtraInfo string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time +} + +func (t CDRsql) TableName() string { + return utils.CDRsTBL +} + +type SMCostSQL struct { + ID int64 + Cgrid string + RunID string + OriginHost string + OriginID string + CostSource string + Usage float64 + CostDetails string + CreatedAt time.Time + DeletedAt *time.Time +} + +func (t SMCostSQL) TableName() string { + return utils.SMCostsTBL +} + +type TBLVersion struct { + ID uint + Item string + Version int64 +} + +func (t TBLVersion) TableName() string { + return utils.TBLVersions +} diff --git a/engine/responder_test.go b/engine/responder_test.go index 5eb31fd53..824374b9b 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -473,7 +473,11 @@ func TestResponderGetLCR(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry) } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { +<<<<<<< HEAD t.Errorf("Expecting: %s\n, received: %+v", utils.ToJSON(eLcLcr.SupplierCosts), utils.ToJSON(lcrLc.SupplierCosts)) +======= + t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } /* // Test *qos_threshold strategy here, @@ -505,6 +509,7 @@ func TestResponderGetLCR(t *testing.T) { t.Error(err) } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) +<<<<<<< HEAD } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) @@ -535,6 +540,38 @@ func TestResponderGetLCR(t *testing.T) { } +======= + + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) + } + + cdr := &CDR{AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + cdr = &CDR{AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} + rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) + + eQTLcr = &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", + Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, + QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}}, + }, + } + if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { + t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) + } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { + t.Errorf("Expecting: %s, received: %s", + utils.ToJSON(eQTLcr.SupplierCosts), utils.ToJSON(lcrQT.SupplierCosts)) + } + + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update // Test *qos strategy here cdQos := &CallDescriptor{ TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 7cf9f7db1..0978785d0 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -725,7 +725,11 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { OriginID: smc.OriginID, CostSource: smc.CostSource, CostDetails: smc.CostDetails.AsJSON(), +<<<<<<< HEAD Usage: smc.Usage.Nanoseconds(), +======= + Usage: smc.Usage, +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update CreatedAt: time.Now(), } if tx.Save(cd).Error != nil { // Check further since error does not properly reflect duplicates here (sql: no rows in result set) @@ -811,7 +815,11 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { } tx = self.db.Begin() cdrSql.UpdatedAt = time.Now() +<<<<<<< HEAD updated := tx.Model(&CDRsql{}).Where(&CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) +======= + updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update if updated.Error != nil { tx.Rollback() return updated.Error @@ -997,6 +1005,7 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, maxUsage, err := utils.ParseDurationWithNanosecs(qryFltr.MaxUsage) if err != nil { return nil, 0, err +<<<<<<< HEAD } if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) @@ -1005,6 +1014,32 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } } +======= + } + if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage + q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) + } else { + q = q.Where("usage < ?", maxUsage.Nanoseconds()) + } + + } + if len(qryFltr.MinPDD) != 0 { + if minPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd >= ?", minPDD.Nanoseconds()) + } + + } + if len(qryFltr.MaxPDD) != 0 { + if maxPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd < ?", maxPDD.Nanoseconds()) + } + } + +>>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { q = q.Where("cost >= ?", *qryFltr.MinCost) diff --git a/engine/version.go b/engine/version.go index b17a29228..b0959e32c 100644 --- a/engine/version.go +++ b/engine/version.go @@ -24,6 +24,9 @@ import ( "github.com/cgrates/cgrates/utils" ) +// Versions will keep trac of various item versions +type Versions map[string]int64 // map[item]versionNr + func CheckVersions(storage Storage) error { // get current db version storType := storage.GetStorageType() @@ -104,29 +107,6 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } -func CurrentDBVersions(storType string) Versions { - dataDbVersions := CurrentDataDBVersions() - storDbVersions := CurrentStorDBVersions() - - allVersions := make(Versions) - for k, v := range dataDbVersions { - allVersions[k] = v - } - for k, v := range storDbVersions { - allVersions[k] = v - } - - switch storType { - case utils.MONGO, utils.MAPSTOR: - return allVersions - case utils.POSTGRES, utils.MYSQL: - return storDbVersions - case utils.REDIS: - return dataDbVersions - } - return nil -} - func CurrentDataDBVersions() Versions { return Versions{ utils.StatS: 2, @@ -184,5 +164,25 @@ func CurrentStorDBVersions() Versions { } } -// Versions will keep trac of various item versions -type Versions map[string]int64 // map[item]versionNr +func CurrentDBVersions(storType string) Versions { + dataDbVersions := CurrentDataDBVersions() + storDbVersions := CurrentStorDBVersions() + + allVersions := make(Versions) + for k, v := range dataDbVersions { + allVersions[k] = v + } + for k, v := range storDbVersions { + allVersions[k] = v + } + + switch storType { + case utils.MONGO, utils.MAPSTOR: + return allVersions + case utils.POSTGRES, utils.MYSQL: + return storDbVersions + case utils.REDIS: + return dataDbVersions + } + return nil +} From 6042f45d5efe4f709a4cee88fde4fd644f07fc7b Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Nov 2017 13:21:01 +0100 Subject: [PATCH 66/75] CacheS in engine, config cache exporting update --- cmd/cgr-engine/rater.go | 2 +- cmd/cgr-migrator/cgr-migrator.go | 3 ++- engine/libtest.go | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index 653193c50..cf0b5b21b 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -44,7 +44,7 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC go func() { defer close(cacheTaskChan) var dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs, alsIDs, rvAlsIDs, rspIDs, resIDs, stqIDs, stqpIDs, thIDs, thpIDs, fltrIDs, lcrPrfIDs []string - if cCfg, has := ccacheCfg[utils.CacheDestinations]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheDestinations]; !has || !cCfg.Precache { dstIDs = make([]string, 0) // Don't cache any } if cCfg, has := cacheCfg[utils.CacheReverseDestinations]; !has || !cCfg.Precache { diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index 80f5b2b89..6b99f6a9b 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -66,7 +66,7 @@ var ( inStorDBUser = flag.String("stordb_user", config.CgrConfig().StorDBUser, "The storDb user to sign in as.") inStorDBPass = flag.String("stordb_passwd", config.CgrConfig().StorDBPass, "The storDb user's password.") - loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") + loadHistorySize = flag.Int("load_history_size", config.CgrConfig().LoadHistorySize, "Limit the number of records in the load history") dbDataEncoding = flag.String("dbData_encoding", config.CgrConfig().DBDataEncoding, "The encoding used to store object Data in strings") inDBDataEncoding = flag.String("in_dbData_encoding", "", "The encoding used to store object Data in strings") @@ -86,6 +86,7 @@ func main() { log.Print("Initializing DataDB:", *outDataDBType) log.Print("Initializing storDB:", *outStorDBType) } + var dmOUT *engine.DataManager dmOUT, _ = engine.ConfigureDataStorage(*outDataDBType, *outDataDBHost, *outDataDBPort, *outDataDBName, *outDataDBUser, *outDataDBPass, *dbDataEncoding, config.CgrConfig().CacheCfg(), *loadHistorySize) storDB, err := engine.ConfigureStorStorage(*outStorDBType, *outStorDBHost, *outStorDBPort, *outStorDBName, *outStorDBUser, *outStorDBPass, *dbDataEncoding, diff --git a/engine/libtest.go b/engine/libtest.go index 31dc28216..9664aedc9 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -34,7 +34,8 @@ import ( ) func InitDataDb(cfg *config.CGRConfig) error { - dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) + dm, err := ConfigureDataStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort, cfg.DataDbName, + cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding, cfg.CacheCfg(), cfg.LoadHistorySize) if err != nil { return err } From 143e8b3db8156c19eef2dd1296be007834fe86c6 Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Nov 2017 13:48:00 +0100 Subject: [PATCH 67/75] Engine tests fixes --- engine/version.go | 1 + engine/versions_it_test.go | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/engine/version.go b/engine/version.go index b0959e32c..4f682d71a 100644 --- a/engine/version.go +++ b/engine/version.go @@ -107,6 +107,7 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } +<<<<<<< HEAD func CurrentDataDBVersions() Versions { return Versions{ utils.StatS: 2, diff --git a/engine/versions_it_test.go b/engine/versions_it_test.go index 6dd14e163..2d1eeecb5 100644 --- a/engine/versions_it_test.go +++ b/engine/versions_it_test.go @@ -182,16 +182,9 @@ func testVersion(t *testing.T) { storType = storageDb.GetStorageType() switch storType { case utils.MONGO, utils.MAPSTOR: -<<<<<<< HEAD - currentVersion = Versions{utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, - utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} - testVersion = Versions{utils.Accounts: 1, utils.Actions: 2, utils.ActionTriggers: 2, - utils.ActionPlans: 2, utils.SharedGroups: 2, utils.COST_DETAILS: 2, utils.CDRs: 2} -======= currentVersion = allVersions testVersion = allVersions testVersion[utils.Accounts] = 1 ->>>>>>> Added move feature(to migrate data from one db to another) and updated GetTPIds , IsDBempty and the versioning accordingly test = "Migration needed: please backup cgr data and run : " case utils.POSTGRES, utils.MYSQL: currentVersion = storDbVersions From 30c7d2139d394c88221861a58d6055775b6f1e60 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 13:33:11 +0100 Subject: [PATCH 68/75] Integration test fixes --- general_tests/a1_it_test.go | 4 ++-- sessionmanager/smgeneric.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index 4f9960e73..cd9ca0110 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -148,7 +148,7 @@ func TestA1itDataSession1(t *testing.T) { var maxUsage float64 if err := a1rpc.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 10240 { + } else if maxUsage != 0.000010240 { t.Error("Received: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ @@ -174,7 +174,7 @@ func TestA1itDataSession1(t *testing.T) { if err := a1rpc.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 2097152 { + } else if maxUsage != 0.002097152 { t.Error("Bad max usage: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index ca9375d44..2f53e511e 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -369,7 +369,8 @@ func (smg *SMGeneric) sessionStart(evStart SMGenericEvent, return nil, nil // ToDo: handle here also debits } var sessionRuns []*engine.SessionRun - if err := smg.rals.Call("Responder.GetSessionRuns", evStart.AsCDR(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { + if err := smg.rals.Call("Responder.GetSessionRuns", + evStart.AsCDR(smg.cgrCfg, smg.Timezone), &sessionRuns); err != nil { return nil, err } else if len(sessionRuns) == 0 { return nil, nil From e07352130118d72a81beb5815bedd356f022ac93 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 18:20:17 +0100 Subject: [PATCH 69/75] Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests --- sessionmanager/data_it_test.go | 326 +++++++++++++++++++++++++++++ sessionmanager/smgreplc_it_test.go | 8 + utils/consts.go | 166 +++++++-------- 3 files changed, 415 insertions(+), 85 deletions(-) diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index 41c8ebe76..546e9be93 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -298,10 +298,46 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { utils.CATEGORY: "data", utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, +<<<<<<< HEAD utils.SETUP_TIME: "2016-01-05 18:30:50", utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1024", // 8 MB utils.LastUsed: "5120", // 5 MB +======= + utils.USAGE: "1048576", + utils.LastUsed: "20000", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49998883840.000000 // 20480 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1088576 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123492", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "20000", +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) @@ -383,7 +419,38 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } +<<<<<<< HEAD if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { +======= +} + +func TestSMGDataDerivedChargingNoCredit(t *testing.T) { + var acnt *engine.Account + attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1011"} + eAcntVal := 50000.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + smgEv := SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.VOICE, + utils.ACCID: "1234967", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1011", + utils.SUBJECT: "1011", + utils.DESTINATION: "+49", + utils.CATEGORY: "call", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:49", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "100", + } + var maxUsage float64 + if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests t.Error(err) } else if reply != utils.OK { t.Errorf("Received reply: %s", reply) @@ -498,7 +565,11 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "4096", // 3MB } +<<<<<<< HEAD var maxUsage int64 +======= + var maxUsage float64 +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -519,6 +590,7 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { t.Errorf("wrong active sessions: %d", int64(aSessions[0].Usage)) } smgEv = SMGenericEvent{ +<<<<<<< HEAD utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123495", @@ -539,6 +611,25 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { t.Error(err) } if maxUsage != 4096 { +======= + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123495", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "20000", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests t.Error("Bad max usage: ", maxUsage) } eAcntVal = 97280.000000 // 20480 @@ -596,7 +687,11 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2048", } +<<<<<<< HEAD var maxUsage int64 +======= + var maxUsage float64 +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -612,14 +707,85 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) +<<<<<<< HEAD } else if len(aSessions) != 1 || int64(aSessions[0].Usage) != 2048 { t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) +======= + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, + utils.ACCID: "123496", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "0", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, +<<<<<<< HEAD utils.ACCID: "123495", +======= + utils.ACCID: "123496", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "0", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123496", +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests utils.DIRECTION: utils.OUT, utils.ACCOUNT: acntAttrs.Account, utils.SUBJECT: acntAttrs.Account, @@ -758,7 +924,11 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2048", } +<<<<<<< HEAD var maxUsage int64 +======= + var maxUsage float64 +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -774,6 +944,7 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) +<<<<<<< HEAD } else if len(aSessions) != 1 || int64(aSessions[0].Usage) != 2048 { t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) @@ -782,5 +953,160 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) +======= + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123497", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "600", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049176 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123497", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "600", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049776 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123497", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "600", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050376 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123497", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.USAGE: "1048576", + utils.LastUsed: "600", + } + if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 1.048576e+06 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 49996712960.000000 // 0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050976 { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT", + utils.TOR: utils.DATA, + utils.ACCID: "123497", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "1010", + utils.SUBJECT: "1010", + utils.DESTINATION: "222", + utils.CATEGORY: "data", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.LastUsed: "0", + } + var rpl string + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { + t.Error(err) + } + eAcntVal = 49997757440.000000 // 10240 (from the start) + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { + t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests } } diff --git a/sessionmanager/smgreplc_it_test.go b/sessionmanager/smgreplc_it_test.go index 21c664d37..1b551c8ba 100644 --- a/sessionmanager/smgreplc_it_test.go +++ b/sessionmanager/smgreplc_it_test.go @@ -151,7 +151,11 @@ func TestSMGRplcUpdate(t *testing.T) { utils.ACCID: "123451", utils.USAGE: "1m", } +<<<<<<< HEAD var maxUsage time.Duration +======= + var maxUsage float64 +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRplcSlvRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) @@ -256,7 +260,11 @@ func TestSMGRplcManualReplicate(t *testing.T) { utils.USAGE: "1m30s", } for _, smgEv := range []SMGenericEvent{smgEv1, smgEv2} { +<<<<<<< HEAD var maxUsage time.Duration +======= + var maxUsage float64 +>>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } diff --git a/utils/consts.go b/utils/consts.go index 9041fd28b..beafe895a 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -480,6 +480,87 @@ const ( Disabled = "Disabled" Action = "Action" ThresholdSv1ProcessEvent = "ThresholdSv1.ProcessEvent" + MetaNow = "*now" + TpRatingPlans = "TpRatingPlans" + TpLcrs = "TpLcrs" + TpFilters = "TpFilters" + TpDestinationRates = "TpDestinationRates" + TpActionTriggers = "TpActionTriggers" + TpAccountActions = "TpAccountActions" + TpActionPlans = "TpActionPlans" + TpActions = "TpActions" + TpDerivedCharges = "TpDerivedCharges" + TpThresholds = "TpThresholds" + TpStats = "TpStats" + TpSharedGroups = "TpSharedGroups" + TpRatingProfiles = "TpRatingProfiles" + TpResources = "TpResources" + TpRates = "TpRates" + TpTiming = "TpTiming" + TpResource = "TpResource" + TpAliases = "TpAliases" + TpUsers = "TpUsers" + TpDerivedChargersV = "TpDerivedChargers" + TpCdrStats = "TpCdrStats" + TpDestinations = "TpDestinations" + TpLCR = "TpLCR" + TpRatingPlan = "TpRatingPlan" + TpRatingProfile = "TpRatingProfile" + Timing = "Timing" + RQF = "RQF" + Resource = "Resource" + ReverseAlias = "ReverseAlias" + Alias = "Alias" + User = "User" + Subscribers = "Subscribers" + DerivedChargersV = "DerivedChargers" + CdrStats = "CdrStats" + Destinations = "Destinations" + ReverseDestinations = "ReverseDestinations" + LCR = "LCR" + RatingPlan = "RatingPlan" + RatingProfile = "RatingProfile" + MetaRatingPlans = "*ratingplans" + MetaRatingProfile = "*ratingprofile" + MetaDestinations = "*destinations" + MetaReverseDestinations = "*reversedestinations" + MetaLCR = "*lcr" + MetaCdrStats = "*cdrstats" + MetaTiming = "*Timing" + MetaRQF = "*RQF" + MetaResource = "*Resource" + MetaReverseAlias = "*ReverseAlias" + MetaAlias = "*Alias" + MetaUser = "*User" + MetaSubscribers = "*Subscribers" + MetaDerivedChargersV = "*DerivedChargers" + MetaTpRatingPlans = "*TpRatingPlans" + MetaTpLcrs = "*TpLcrs" + MetaTpFilters = "*TpFilters" + MetaTpDestinationRates = "*TpDestinationRates" + MetaTpActionTriggers = "*TpActionTriggers" + MetaTpAccountActions = "*TpAccountActions" + MetaTpActionPlans = "*TpActionPlans" + MetaTpActions = "*TpActions" + MetaTpDerivedCharges = "*TpDerivedCharges" + MetaTpThresholds = "*TpThresholds" + MetaTpStats = "*TpStats" + MetaTpSharedGroups = "*TpSharedGroups" + MetaTpRatingProfiles = "*TpRatingProfiles" + MetaTpResources = "*TpResources" + MetaTpRates = "*TpRates" + MetaTpTiming = "*TpTiming" + MetaTpResource = "*TpResource" + MetaTpAliases = "*TpAliases" + MetaTpUsers = "*TpUsers" + MetaTpDerivedChargersV = "*TpDerivedChargers" + MetaTpCdrStats = "*TpCdrStats" + MetaTpDestinations = "*TpDestinations" + MetaTpLCR = "*TpLCR" + MetaTpRatingPlan = "*TpRatingPlan" + MetaTpRatingProfile = "*TpRatingProfile" + MetaStorDB = "*StorDB" + MetaDataDB = "*DataDB" SMGenericV2UpdateSession = "SMGenericV2.UpdateSession" SMGenericV2InitiateSession = "SMGenericV2.InitiateSession" SMGenericV1UpdateSession = "SMGenericV1.UpdateSession" @@ -495,7 +576,6 @@ const ( MetaTCC = "*tcc" MetaPDD = "*pdd" MetaDDC = "*ddc" - MetaNow = "*now" ) //Migrator Metas @@ -509,92 +589,8 @@ const ( MetaSharedGroups = "*shared_groups" MetaStats = "*stats" MetaThresholds = "*thresholds" - MetaRatingPlans = "*ratingplans" - MetaRatingProfile = "*ratingprofile" - MetaDestinations = "*destinations" - MetaReverseDestinations = "*reversedestinations" - MetaLCR = "*lcr" - MetaCdrStats = "*cdrstats" - MetaTiming = "*Timing" - MetaRQF = "*RQF" - MetaResource = "*Resource" - MetaReverseAlias = "*ReverseAlias" - MetaAlias = "*Alias" - MetaUser = "*User" - MetaSubscribers = "*Subscribers" - MetaDerivedChargersV = "*DerivedChargers" Migrator = "migrator" UnsupportedMigrationTask = "unsupported migration task" - MetaTpRatingPlans = "*TpRatingPlans" - MetaTpLcrs = "*TpLcrs" - MetaTpFilters = "*TpFilters" - MetaTpDestinationRates = "*TpDestinationRates" - MetaTpActionTriggers = "*TpActionTriggers" - MetaTpAccountActions = "*TpAccountActions" - MetaTpActionPlans = "*TpActionPlans" - MetaTpActions = "*TpActions" - MetaTpDerivedCharges = "*TpDerivedCharges" - MetaTpThresholds = "*TpThresholds" - MetaTpStats = "*TpStats" - MetaTpSharedGroups = "*TpSharedGroups" - MetaTpRatingProfiles = "*TpRatingProfiles" - MetaTpResources = "*TpResources" - MetaTpRates = "*TpRates" - MetaTpTiming = "*TpTiming" - MetaTpResource = "*TpResource" - MetaTpAliases = "*TpAliases" - MetaTpUsers = "*TpUsers" - MetaTpDerivedChargersV = "*TpDerivedChargers" - MetaTpCdrStats = "*TpCdrStats" - MetaTpDestinations = "*TpDestinations" - MetaTpLCR = "*TpLCR" - MetaTpRatingPlan = "*TpRatingPlan" - MetaTpRatingProfile = "*TpRatingProfile" - MetaStorDB = "*StorDB" - MetaDataDB = "*DataDB" -) - -//versions -const ( - TpRatingPlans = "TpRatingPlans" - TpLcrs = "TpLcrs" - TpFilters = "TpFilters" - TpDestinationRates = "TpDestinationRates" - TpActionTriggers = "TpActionTriggers" - TpAccountActions = "TpAccountActions" - TpActionPlans = "TpActionPlans" - TpActions = "TpActions" - TpDerivedCharges = "TpDerivedCharges" - TpThresholds = "TpThresholds" - TpStats = "TpStats" - TpSharedGroups = "TpSharedGroups" - TpRatingProfiles = "TpRatingProfiles" - TpResources = "TpResources" - TpRates = "TpRates" - TpTiming = "TpTiming" - TpResource = "TpResource" - TpAliases = "TpAliases" - TpUsers = "TpUsers" - TpDerivedChargersV = "TpDerivedChargers" - TpCdrStats = "TpCdrStats" - TpDestinations = "TpDestinations" - TpLCR = "TpLCR" - TpRatingPlan = "TpRatingPlan" - TpRatingProfile = "TpRatingProfile" - Timing = "Timing" - RQF = "RQF" - Resource = "Resource" - ReverseAlias = "ReverseAlias" - Alias = "Alias" - User = "User" - Subscribers = "Subscribers" - DerivedChargersV = "DerivedChargers" - CdrStats = "CdrStats" - Destinations = "Destinations" - ReverseDestinations = "ReverseDestinations" - LCR = "LCR" - RatingPlan = "RatingPlan" - RatingProfile = "RatingProfile" ) func buildCacheInstRevPrefixes() { From f51fec1c31bf9d9ceec091f79c5e84396f2c7721 Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 9 Nov 2017 18:27:09 +0100 Subject: [PATCH 70/75] Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates --- engine/models.go | 2 +- engine/storage_sql.go | 4 --- sessionmanager/data_it_test.go | 55 ++++++++++++++++++++++-------- sessionmanager/smgreplc_it_test.go | 8 ----- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/engine/models.go b/engine/models.go index 230de04b5..8b425b560 100755 --- a/engine/models.go +++ b/engine/models.go @@ -574,7 +574,7 @@ type SMCostSQL struct { OriginHost string OriginID string CostSource string - Usage float64 + Usage int64 CostDetails string CreatedAt time.Time DeletedAt *time.Time diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 0978785d0..bcdec5008 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -725,11 +725,7 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { OriginID: smc.OriginID, CostSource: smc.CostSource, CostDetails: smc.CostDetails.AsJSON(), -<<<<<<< HEAD Usage: smc.Usage.Nanoseconds(), -======= - Usage: smc.Usage, ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update CreatedAt: time.Now(), } if tx.Save(cd).Error != nil { // Check further since error does not properly reflect duplicates here (sql: no rows in result set) diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index 546e9be93..a7835b57a 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -298,46 +298,50 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { utils.CATEGORY: "data", utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, -<<<<<<< HEAD utils.SETUP_TIME: "2016-01-05 18:30:50", utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "1024", // 8 MB utils.LastUsed: "5120", // 5 MB -======= - utils.USAGE: "1048576", - utils.LastUsed: "20000", } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 1.048576e+06 { + if maxUsage != 8192 { t.Error("Bad max usage: ", maxUsage) } - eAcntVal = 49998883840.000000 // 20480 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + eAcntVal = 87040.000000 // 15MB used + if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) + } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { + t.Errorf("Expected: %f, received: %f", totalVal) } if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1088576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) + } else if len(aSessions) != 1 || + aSessions[0].Usage != time.Duration(15360) { + t.Errorf("wrong active sessions: %f", aSessions[0].Usage) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123492", utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", + utils.ACCOUNT: acntAttrs.Account, + utils.SUBJECT: acntAttrs.Account, + utils.DESTINATION: utils.DATA, utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", + utils.TENANT: acntAttrs.Tenant, utils.REQTYPE: utils.META_PREPAID, +<<<<<<< HEAD utils.USAGE: "1048576", utils.LastUsed: "20000", >>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests +======= + utils.SETUP_TIME: "2016-01-05 18:30:50", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "1024", // 8 MB + utils.LastUsed: "5120", // 5 MB +>>>>>>> Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates } if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) @@ -419,9 +423,30 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } +<<<<<<< HEAD <<<<<<< HEAD if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { ======= +======= + if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Received reply: %s", reply) + } + time.Sleep(time.Duration(10) * time.Millisecond) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + Accounts: []string{acntAttrs.Account}} + if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if cdrs[0].Usage != "13312" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } +>>>>>>> Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates } func TestSMGDataDerivedChargingNoCredit(t *testing.T) { diff --git a/sessionmanager/smgreplc_it_test.go b/sessionmanager/smgreplc_it_test.go index 1b551c8ba..21c664d37 100644 --- a/sessionmanager/smgreplc_it_test.go +++ b/sessionmanager/smgreplc_it_test.go @@ -151,11 +151,7 @@ func TestSMGRplcUpdate(t *testing.T) { utils.ACCID: "123451", utils.USAGE: "1m", } -<<<<<<< HEAD var maxUsage time.Duration -======= - var maxUsage float64 ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRplcSlvRPC.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) @@ -260,11 +256,7 @@ func TestSMGRplcManualReplicate(t *testing.T) { utils.USAGE: "1m30s", } for _, smgEv := range []SMGenericEvent{smgEv1, smgEv2} { -<<<<<<< HEAD var maxUsage time.Duration -======= - var maxUsage float64 ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRplcMstrRPC.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) } From 9c19fb469cc0ca89e471ed5b404399e7d2c5d80e Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 12 Nov 2017 19:26:07 +0100 Subject: [PATCH 71/75] *voice balance format change into nanoseconds from seconds, some test fixes --- general_tests/ddazmbl1_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index f67bee41c..2ea863922 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -65,8 +65,12 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` thresholds := `` filters := `` lcrprofiles := `` - csvr := engine.NewTpReader(dataDB.DataDB(), engine.NewStringCSVStorage(',', destinations, timings, rates, destinationRates, ratingPlans, ratingProfiles, - sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, derivedCharges, cdrStats, users, aliases, resLimits, stats, thresholds, filters, lcrprofiles), "", "") + csvr := engine.NewTpReader(dataDB.DataDB(), + engine.NewStringCSVStorage(',', destinations, timings, rates, + destinationRates, ratingPlans, ratingProfiles, + sharedGroups, lcrs, actions, actionPlans, actionTriggers, accountActions, + derivedCharges, cdrStats, users, aliases, resLimits, stats, + thresholds, filters, lcrprofiles), "", "") if err := csvr.LoadDestinations(); err != nil { t.Fatal(err) } @@ -113,12 +117,8 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` t.Error("No account saved") } cache.Flush() -<<<<<<< HEAD /* dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) -======= - dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) ->>>>>>> LCRProfile(2) if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) From 02d13bd296e43f9f40beb95f1de4b0f5b4dfefc6 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 17 Nov 2017 17:27:39 +0200 Subject: [PATCH 72/75] Update integration test --- general_tests/a1_it_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/general_tests/a1_it_test.go b/general_tests/a1_it_test.go index cd9ca0110..4f9960e73 100644 --- a/general_tests/a1_it_test.go +++ b/general_tests/a1_it_test.go @@ -148,7 +148,7 @@ func TestA1itDataSession1(t *testing.T) { var maxUsage float64 if err := a1rpc.Call(utils.SMGenericV2InitiateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 0.000010240 { + } else if maxUsage != 10240 { t.Error("Received: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ @@ -174,7 +174,7 @@ func TestA1itDataSession1(t *testing.T) { if err := a1rpc.Call(utils.SMGenericV2UpdateSession, smgEv, &maxUsage); err != nil { t.Error(err) - } else if maxUsage != 0.002097152 { + } else if maxUsage != 2097152 { t.Error("Bad max usage: ", maxUsage) } smgEv = sessionmanager.SMGenericEvent{ From d5b60261c0fd3eab31dd7f6b2ffa594cb56b7963 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 20 Nov 2017 18:05:50 +0100 Subject: [PATCH 73/75] Merge fixes --- cmd/cgr-engine/rater.go | 2 +- cmd/cgr-migrator/cgr-migrator.go | 6 ++++-- engine/version.go | 1 - general_tests/ddazmbl1_test.go | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/cgr-engine/rater.go b/cmd/cgr-engine/rater.go index cf0b5b21b..a2a9720a5 100755 --- a/cmd/cgr-engine/rater.go +++ b/cmd/cgr-engine/rater.go @@ -104,7 +104,7 @@ func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneC if cCfg, has := cacheCfg[utils.CacheFilters]; !has || !cCfg.Precache { fltrIDs = make([]string, 0) } - if cCfg, has := cfg.CacheConfig[utils.CacheLCRProfiles]; !has || !cCfg.Precache { + if cCfg, has := cacheCfg[utils.CacheLCRProfiles]; !has || !cCfg.Precache { lcrPrfIDs = make([]string, 0) } diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index 6b99f6a9b..465db9b37 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -121,8 +121,10 @@ func main() { } } if *inStorDBType != "" { - instorDB, err = engine.ConfigureStorStorage(*inStorDBType, *inStorDBHost, *inStorDBPort, *inStorDBName, *inStorDBUser, *inStorDBPass, *inDBDataEncoding, - config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) + instorDB, err = engine.ConfigureStorStorage(*inStorDBType, *inStorDBHost, *inStorDBPort, + *inStorDBName, *inStorDBUser, *inStorDBPass, *inDBDataEncoding, + config.CgrConfig().StorDBMaxOpenConns, config.CgrConfig().StorDBMaxIdleConns, + config.CgrConfig().StorDBConnMaxLifetime, config.CgrConfig().StorDBCDRSIndexes) if err != nil { log.Fatal(err) } diff --git a/engine/version.go b/engine/version.go index 4f682d71a..b0959e32c 100644 --- a/engine/version.go +++ b/engine/version.go @@ -107,7 +107,6 @@ func (vers Versions) Compare(curent Versions, storType string) string { return "" } -<<<<<<< HEAD func CurrentDataDBVersions() Versions { return Versions{ utils.StatS: 2, diff --git a/general_tests/ddazmbl1_test.go b/general_tests/ddazmbl1_test.go index 2ea863922..f627e369a 100644 --- a/general_tests/ddazmbl1_test.go +++ b/general_tests/ddazmbl1_test.go @@ -119,7 +119,6 @@ TOPUP10_AT,TOPUP10_AC1,ASAP,10` cache.Flush() /* dataDB.LoadDataDBCache(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - if cachedDests := cache.CountEntries(utils.DESTINATION_PREFIX); cachedDests != 0 { t.Error("Wrong number of cached destinations found", cachedDests) } From 16d477ccd96387bc9bbaa2da5fb3d9f4a1964b14 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 21 Nov 2017 15:14:52 +0100 Subject: [PATCH 74/75] Merge test fixes --- engine/cdr.go | 35 ------------------------ engine/cdr_test.go | 22 --------------- engine/cgrcdr_test.go | 4 --- engine/models.go | 58 ---------------------------------------- engine/responder_test.go | 36 ------------------------- engine/storage_sql.go | 34 ++--------------------- 6 files changed, 2 insertions(+), 187 deletions(-) diff --git a/engine/cdr.go b/engine/cdr.go index 5f6b246d8..6c33eef33 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -175,11 +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: -<<<<<<< HEAD return cdr.Usage.String() -======= - return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update case utils.MEDI_RUNID: return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: @@ -384,11 +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) -<<<<<<< HEAD } else if frkStorCdr.Usage, err = utils.ParseDurationWithNanosecs(durStr); err != nil { -======= - } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } ratedStr := cdr.FieldAsString(ratedFld) @@ -433,11 +425,7 @@ func (cdr *CDR) AsExternalCDR() *ExternalCDR { Destination: cdr.Destination, SetupTime: cdr.SetupTime.Format(time.RFC3339), AnswerTime: cdr.AnswerTime.Format(time.RFC3339), -<<<<<<< HEAD Usage: usageStr, -======= - Usage: cdr.FormatUsage(utils.SECONDS), ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: cdr.ExtraFields, CostSource: cdr.CostSource, Cost: cdr.Cost, @@ -566,11 +554,7 @@ func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { } else { durVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -<<<<<<< HEAD return utils.ParseDurationWithNanosecs(durVal) -======= - return utils.ParseDurationWithSecs(durVal) ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { @@ -784,11 +768,7 @@ func (cdr *CDR) AsExportMap(exportFields []*config.CfgCdrField, httpSkipTlsCheck // AsCDRsTBL converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { cdrSql = new(CDRsql) -<<<<<<< HEAD cdrSql.Cgrid = cdr.CGRID -======= - cdrSql.CGRID = cdr.CGRID ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdrSql.RunID = cdr.RunID cdrSql.OriginHost = cdr.OriginHost cdrSql.Source = cdr.Source @@ -815,19 +795,12 @@ func (cdr *CDR) AsCDRsql() (cdrSql *CDRsql) { // NewCDRFromSQL converts the CDRsql into CDR func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr = new(CDR) -<<<<<<< HEAD cdr.CGRID = cdrSql.Cgrid -======= - cdr.CGRID = cdrSql.CGRID ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.RunID = cdrSql.RunID cdr.OriginHost = cdrSql.OriginHost cdr.Source = cdrSql.Source cdr.OriginID = cdrSql.OriginID -<<<<<<< HEAD cdr.OrderID = cdrSql.ID -======= ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.ToR = cdrSql.TOR cdr.RequestType = cdrSql.RequestType cdr.Tenant = cdrSql.Tenant @@ -838,10 +811,6 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { cdr.SetupTime = cdrSql.SetupTime cdr.AnswerTime = cdrSql.AnswerTime cdr.Usage = time.Duration(cdrSql.Usage) -<<<<<<< HEAD -======= - ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update cdr.CostSource = cdrSql.CostSource cdr.Cost = cdrSql.Cost cdr.ExtraInfo = cdrSql.ExtraInfo @@ -851,11 +820,7 @@ func NewCDRFromSQL(cdrSql *CDRsql) (cdr *CDR, err error) { } } if cdrSql.CostDetails != "" { -<<<<<<< HEAD if err = json.Unmarshal([]byte(cdrSql.CostDetails), &cdr.CostDetails); err != nil { -======= - if err = json.Unmarshal([]byte(cdrSql.CostDetails), cdr.CostDetails); err != nil { ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update return nil, err } } diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 858d1f750..94a4b2451 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -98,11 +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) || -<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s" || -======= - cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" || ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update 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"] || @@ -122,11 +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), -<<<<<<< HEAD cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10s", -======= - cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10", ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update 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"], @@ -403,11 +395,7 @@ func TestCDRAsExternalCDR(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), -<<<<<<< HEAD RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10 * time.Second), Cost: 1.01, -======= - RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} expectOutCdr := &ExternalCDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -415,11 +403,7 @@ func TestCDRAsExternalCDR(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, -<<<<<<< HEAD Usage: "10s", Cost: 1.01, CostDetails: "null", -======= - Usage: "0.00000001", Cost: 1.01, CostDetails: "null", ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) @@ -513,15 +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", -<<<<<<< HEAD Usage: "10", } eCD := &CallDescriptor{CgrID: "c4630df20b2a0c5b11311e4b5a8c3178cf314344", TOR: req.ToR, -======= - Usage: "0.00000001", - } - eCD := &CallDescriptor{CgrID: "48ca1a2eb82b028fbfc809e36a585061a775ffc3", TOR: req.ToR, ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update Direction: utils.OUT, Tenant: req.Tenant, Category: req.Category, Account: req.Account, Subject: req.Subject, Destination: req.Destination, diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index 106cbc3ba..71ad57a00 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -38,11 +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", -<<<<<<< HEAD utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} -======= - utils.USAGE: "10", "field_extr1": "val_extr1", "fieldextr2": "valextr2"} ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), ToR: utils.VOICE, OriginID: cgrCdr[utils.ACCID], diff --git a/engine/models.go b/engine/models.go index 8b425b560..2f1379da6 100755 --- a/engine/models.go +++ b/engine/models.go @@ -535,61 +535,3 @@ type TpLCR struct { Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time } - -type CDRsql struct { - ID int64 - CGRID string - RunID string - OriginHost string - Source string - OriginID string - TOR string - RequestType string - Tenant string - Category string - Account string - Subject string - Destination string - SetupTime time.Time - AnswerTime time.Time - Usage int64 - ExtraFields string - CostSource string - Cost float64 - CostDetails string - ExtraInfo string - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time -} - -func (t CDRsql) TableName() string { - return utils.CDRsTBL -} - -type SMCostSQL struct { - ID int64 - Cgrid string - RunID string - OriginHost string - OriginID string - CostSource string - Usage int64 - CostDetails string - CreatedAt time.Time - DeletedAt *time.Time -} - -func (t SMCostSQL) TableName() string { - return utils.SMCostsTBL -} - -type TBLVersion struct { - ID uint - Item string - Version int64 -} - -func (t TBLVersion) TableName() string { - return utils.TBLVersions -} diff --git a/engine/responder_test.go b/engine/responder_test.go index 824374b9b..56f66754d 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -473,11 +473,7 @@ func TestResponderGetLCR(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry) } else if !reflect.DeepEqual(eLcLcr.SupplierCosts, lcrLc.SupplierCosts) { -<<<<<<< HEAD t.Errorf("Expecting: %s\n, received: %+v", utils.ToJSON(eLcLcr.SupplierCosts), utils.ToJSON(lcrLc.SupplierCosts)) -======= - t.Errorf("Expecting: %+v, received: %+v", eLcLcr.SupplierCosts, lcrLc.SupplierCosts) ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update } /* // Test *qos_threshold strategy here, @@ -509,7 +505,6 @@ func TestResponderGetLCR(t *testing.T) { t.Error(err) } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) -<<<<<<< HEAD } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) @@ -540,38 +535,7 @@ func TestResponderGetLCR(t *testing.T) { } -======= - } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) - } - - cdr := &CDR{AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} - rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) - cdr = &CDR{AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} - rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) - - eQTLcr = &LCRCost{ - Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", - Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;;;4m;;;;;;;;;", Weight: 10.0}, - SupplierCosts: []*LCRSupplierCost{ - &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, - QOS: map[string]float64{PDD: -1, TCD: -1, ACC: -1, TCC: -1, ASR: -1, ACD: -1, DDC: -1}, qosSortParams: []string{"35", "4m"}}, - &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, - QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}}, - }, - } - if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) { - t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry) - } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { - t.Errorf("Expecting: %s, received: %s", - utils.ToJSON(eQTLcr.SupplierCosts), utils.ToJSON(lcrQT.SupplierCosts)) - } - - ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update // Test *qos strategy here cdQos := &CallDescriptor{ TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), diff --git a/engine/storage_sql.go b/engine/storage_sql.go index bcdec5008..4fc0e3baa 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -811,11 +811,8 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error { } tx = self.db.Begin() cdrSql.UpdatedAt = time.Now() -<<<<<<< HEAD - updated := tx.Model(&CDRsql{}).Where(&CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) -======= - updated := tx.Model(&CDRsql{}).Where(&CDRsql{CGRID: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update + updated := tx.Model(&CDRsql{}).Where( + &CDRsql{Cgrid: cdr.CGRID, RunID: cdr.RunID, OriginID: cdr.OriginID}).Updates(cdrSql) if updated.Error != nil { tx.Rollback() return updated.Error @@ -1001,7 +998,6 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, maxUsage, err := utils.ParseDurationWithNanosecs(qryFltr.MaxUsage) if err != nil { return nil, 0, err -<<<<<<< HEAD } if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) @@ -1010,32 +1006,6 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR, } } -======= - } - if self.db.Dialect().GetName() == utils.MYSQL { // MySQL needs escaping for usage - q = q.Where("`usage` < ?", maxUsage.Nanoseconds()) - } else { - q = q.Where("usage < ?", maxUsage.Nanoseconds()) - } - - } - if len(qryFltr.MinPDD) != 0 { - if minPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MinPDD); err != nil { - return nil, 0, err - } else { - q = q.Where("pdd >= ?", minPDD.Nanoseconds()) - } - - } - if len(qryFltr.MaxPDD) != 0 { - if maxPDD, err := utils.ParseDurationWithNanosecs(qryFltr.MaxPDD); err != nil { - return nil, 0, err - } else { - q = q.Where("pdd < ?", maxPDD.Nanoseconds()) - } - } - ->>>>>>> Removing Direction, PDD, DisconnectCause, Supplier from main fields of CDR; MySQL/Postgres storing nanoseconds instead of seconds for usage, tests update if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { q = q.Where("cost >= ?", *qryFltr.MinCost) From 219d6ab6c542c92bbed73edc7537684574d8a8b6 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 21 Nov 2017 16:24:23 +0100 Subject: [PATCH 75/75] Updating data integration test --- sessionmanager/data_it_test.go | 351 --------------------------------- 1 file changed, 351 deletions(-) diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index a7835b57a..41c8ebe76 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -306,46 +306,6 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } - if maxUsage != 8192 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 87040.000000 // 15MB used - if err := smgRPC.Call("ApierV2.GetAccount", acntAttrs, &acnt); err != nil { - t.Error(err) - } else if totalVal := acnt.BalanceMap[utils.DATA].GetTotalValue(); totalVal != eAcntVal { - t.Errorf("Expected: %f, received: %f", totalVal) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || - aSessions[0].Usage != time.Duration(15360) { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123492", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: acntAttrs.Account, - utils.SUBJECT: acntAttrs.Account, - utils.DESTINATION: utils.DATA, - utils.CATEGORY: "data", - utils.TENANT: acntAttrs.Tenant, - utils.REQTYPE: utils.META_PREPAID, -<<<<<<< HEAD - utils.USAGE: "1048576", - utils.LastUsed: "20000", ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests -======= - utils.SETUP_TIME: "2016-01-05 18:30:50", - utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "1024", // 8 MB - utils.LastUsed: "5120", // 5 MB ->>>>>>> Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } if maxUsage != 1024 { t.Error("Bad max usage: ", maxUsage) } @@ -423,59 +383,7 @@ func TestSMGDataLastUsedMultipleUpdates(t *testing.T) { nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) } -<<<<<<< HEAD -<<<<<<< HEAD if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { -======= -======= - if err := smgRPC.Call("SMGenericV1.ProcessCDR", smgEv, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Errorf("Received reply: %s", reply) - } - time.Sleep(time.Duration(10) * time.Millisecond) - var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, - Accounts: []string{acntAttrs.Account}} - if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(cdrs) != 1 { - t.Error("Unexpected number of CDRs returned: ", len(cdrs)) - } else { - if cdrs[0].Usage != "13312" { - t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) - } - } ->>>>>>> Redesigned core to support nanoseconds/data units, cgr-engine memory profiling in commandline options, tests updates -} - -func TestSMGDataDerivedChargingNoCredit(t *testing.T) { - var acnt *engine.Account - attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1011"} - eAcntVal := 50000.0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) - } - smgEv := SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.VOICE, - utils.ACCID: "1234967", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1011", - utils.SUBJECT: "1011", - utils.DESTINATION: "+49", - utils.CATEGORY: "call", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.SETUP_TIME: "2016-01-05 18:30:49", - utils.ANSWER_TIME: "2016-01-05 18:31:05", - utils.USAGE: "100", - } - var maxUsage float64 - if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests t.Error(err) } else if reply != utils.OK { t.Errorf("Received reply: %s", reply) @@ -590,11 +498,7 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "4096", // 3MB } -<<<<<<< HEAD var maxUsage int64 -======= - var maxUsage float64 ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -615,7 +519,6 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { t.Errorf("wrong active sessions: %d", int64(aSessions[0].Usage)) } smgEv = SMGenericEvent{ -<<<<<<< HEAD utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, utils.ACCID: "123495", @@ -636,25 +539,6 @@ func TestSMGDataTTLExpMultiUpdates(t *testing.T) { t.Error(err) } if maxUsage != 4096 { -======= - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123495", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "20000", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests t.Error("Bad max usage: ", maxUsage) } eAcntVal = 97280.000000 // 20480 @@ -712,11 +596,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2048", } -<<<<<<< HEAD var maxUsage int64 -======= - var maxUsage float64 ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -732,85 +612,14 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) -<<<<<<< HEAD } else if len(aSessions) != 1 || int64(aSessions[0].Usage) != 2048 { t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) -======= - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) } smgEv = SMGenericEvent{ utils.EVENT_NAME: "TEST_EVENT", utils.TOR: utils.DATA, - utils.ACCID: "123496", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "0", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, -<<<<<<< HEAD utils.ACCID: "123495", -======= - utils.ACCID: "123496", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "0", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123496", ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests utils.DIRECTION: utils.OUT, utils.ACCOUNT: acntAttrs.Account, utils.SUBJECT: acntAttrs.Account, @@ -949,11 +758,7 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { utils.ANSWER_TIME: "2016-01-05 18:31:05", utils.USAGE: "2048", } -<<<<<<< HEAD var maxUsage int64 -======= - var maxUsage float64 ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests if err := smgRPC.Call("SMGenericV2.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } @@ -969,7 +774,6 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { aSessions := make([]*ActiveSession, 0) if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { t.Error(err) -<<<<<<< HEAD } else if len(aSessions) != 1 || int64(aSessions[0].Usage) != 2048 { t.Errorf("wrong active sessions usage: %d", int64(aSessions[0].Usage)) @@ -978,160 +782,5 @@ func TestSMGDataTTLUsageProtection(t *testing.T) { if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error(err, aSessions) -======= - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049176 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049776 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050376 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.USAGE: "1048576", - utils.LastUsed: "600", - } - if err := smgRPC.Call("SMGenericV2.UpdateSession", smgEv, &maxUsage); err != nil { - t.Error(err) - } - if maxUsage != 1.048576e+06 { - t.Error("Bad max usage: ", maxUsage) - } - eAcntVal = 49996712960.000000 // 0 - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err != nil { - t.Error(err) - } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050976 { - t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds()) - } - smgEv = SMGenericEvent{ - utils.EVENT_NAME: "TEST_EVENT", - utils.TOR: utils.DATA, - utils.ACCID: "123497", - utils.DIRECTION: utils.OUT, - utils.ACCOUNT: "1010", - utils.SUBJECT: "1010", - utils.DESTINATION: "222", - utils.CATEGORY: "data", - utils.TENANT: "cgrates.org", - utils.REQTYPE: utils.META_PREPAID, - utils.LastUsed: "0", - } - var rpl string - if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { - t.Error(err) - } - eAcntVal = 49997757440.000000 // 10240 (from the start) - if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { - t.Error(err) - } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal { - t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue()) - } - if err := smgRPC.Call("SMGenericV1.GetActiveSessions", nil, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) ->>>>>>> Using SMGenericV2 methods returning time.Duration as maxDuration instead of float, updated smg_it tests } }