diff --git a/agents/dmtagent_it_test.go b/agents/dmtagent_it_test.go index 6353203d0..2e6d8f707 100644 --- a/agents/dmtagent_it_test.go +++ b/agents/dmtagent_it_test.go @@ -140,10 +140,10 @@ func TestDmtAgentCCRAsSMGenericEvent(t *testing.T) { if ccr.diamMessage, err = ccr.AsDiameterMessage(); err != nil { t.Error(err) } - eSMGE := sessionmanager.SMGenericEvent{"EventName": DIAMETER_CCR, "AccId": "routinga;1442095190;1476802709", + 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", "ReqType": "*users", "SetupTime": "2015-11-23 12:22:24 +0000 UTC", - "Subject": "*users", "SubscriberId": "4986517174963", "TOR": "*voice", "Tenant": "*users", "Usage": "300"} + "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"} if smge, err := ccr.AsSMGenericEvent(cfgDefaults.DiameterAgentCfg().RequestProcessors[0].CCRFields); err != nil { t.Error(err) } else if !reflect.DeepEqual(eSMGE, smge) { @@ -186,11 +186,11 @@ func TestDmtAgentSendCCRInit(t *testing.T) { if err != nil { t.Fatal(err) } - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 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: "1004", Supplier: "SUPPL1", - SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: 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"}, + 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"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -225,11 +225,11 @@ func TestDmtAgentSendCCRUpdate(t *testing.T) { if !*testIntegration { return } - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 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: "1004", Supplier: "SUPPL1", - SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: 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"}, + 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"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -264,11 +264,11 @@ func TestDmtAgentSendCCRUpdate2(t *testing.T) { if !*testIntegration { return } - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 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: "1004", Supplier: "SUPPL1", - SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: 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"}, + 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"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, false) @@ -302,11 +302,11 @@ func TestDmtAgentSendCCRTerminate(t *testing.T) { if !*testIntegration { return } - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2015, 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: "1004", Supplier: "SUPPL1", - SetupTime: time.Date(2015, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2015, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: 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"}, + 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"}, } ccr := storedCdrToCCR(cdr, "UNIT_TEST", daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DebitInterval, true) @@ -340,8 +340,8 @@ func TestDmtAgentCdrs(t *testing.T) { if !*testIntegration { return } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}} if err := apierRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { diff --git a/agents/libdmt.go b/agents/libdmt.go index 9129872dc..642a15024 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -130,11 +130,11 @@ func usageFromCCR(reqType, reqNr, reqCCTime, usedCCTime int, debitIterval time.D } // Utility function to convert from StoredCdr to CCR struct -func storedCdrToCCR(cdr *engine.StoredCdr, originHost, originRealm string, vendorId int, productName string, +func storedCdrToCCR(cdr *engine.CDR, originHost, originRealm string, vendorId int, productName string, firmwareRev int, debitInterval time.Duration, callEnded bool) *CCR { //sid := "session;" + strconv.Itoa(int(rand.Uint32())) reqType, reqNr, reqCCTime, usedCCTime := disectUsageForCCR(cdr.Usage, debitInterval, callEnded) - ccr := &CCR{SessionId: cdr.CgrId, OriginHost: originHost, OriginRealm: originRealm, DestinationHost: originHost, DestinationRealm: originRealm, + ccr := &CCR{SessionId: cdr.CGRID, OriginHost: originHost, OriginRealm: originRealm, DestinationHost: originHost, DestinationRealm: originRealm, AuthApplicationId: 4, ServiceContextId: cdr.ExtraFields["Service-Context-Id"], CCRequestType: reqType, CCRequestNumber: reqNr, EventTimestamp: cdr.AnswerTime, ServiceIdentifier: 0} ccr.SubscriptionId = make([]struct { @@ -152,7 +152,7 @@ func storedCdrToCCR(cdr *engine.StoredCdr, originHost, originRealm string, vendo ccr.ServiceInformation.INInformation.CallingVlrNumber = cdr.ExtraFields["Calling-Vlr-Number"] ccr.ServiceInformation.INInformation.CallingCellIDOrSAI = cdr.ExtraFields["Calling-CellID-Or-SAI"] ccr.ServiceInformation.INInformation.BearerCapability = cdr.ExtraFields["Bearer-Capability"] - ccr.ServiceInformation.INInformation.CallReferenceNumber = cdr.CgrId + ccr.ServiceInformation.INInformation.CallReferenceNumber = cdr.CGRID ccr.ServiceInformation.INInformation.TimeZone = 0 ccr.ServiceInformation.INInformation.SSPTime = cdr.ExtraFields["SSP-Time"] return ccr diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 794445581..36b4fc86e 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -79,7 +79,7 @@ func TestApierCreateDirs(t *testing.T) { if !*testLocal { return } - for _, pathDir := range []string{cfg.CdreProfiles[utils.META_DEFAULT].ExportDir, "/var/log/cgrates/cdrc/in", "/var/log/cgrates/cdrc/out", cfg.HistoryDir} { + for _, pathDir := range []string{cfg.CdreProfiles[utils.META_DEFAULT].ExportFolder, "/var/log/cgrates/cdrc/in", "/var/log/cgrates/cdrc/out", cfg.HistoryDir} { if err := os.RemoveAll(pathDir); err != nil { t.Fatal("Error removing folder: ", pathDir, err) @@ -312,7 +312,7 @@ func TestApierTPRate(t *testing.T) { if err := rater.Call("ApierV1.GetTPRateIds", AttrGetTPRateIds{rt.TPid, utils.Paginator{}}, &rplyRtIds); err != nil { t.Error("Calling ApierV1.GetTPRateIds, got error: ", err.Error()) } else if !reflect.DeepEqual(expectedRtIds, rplyRtIds) { - t.Errorf("Calling ApierV1.GetTPDestinationIds expected: %v, received: %v", expectedRtIds, rplyRtIds) + t.Errorf("Calling ApierV1.GetTPDestinationIDs expected: %v, received: %v", expectedRtIds, rplyRtIds) } } @@ -1382,7 +1382,7 @@ func TestApierExportCdrsToFile(t *testing.T) { req.CdrFormat = &dryRun tm1, _ := utils.ParseTimeDetectLayout("2013-11-07T08:42:22Z") tm2, _ := utils.ParseTimeDetectLayout("2013-11-07T08:42:23Z") - expectReply := &utils.ExportedFileCdrs{ExportedFilePath: utils.CDRE_DRYRUN, TotalRecords: 2, ExportedCgrIds: []string{utils.Sha1("dsafdsaf", tm1.String()), + expectReply := &utils.ExportedFileCdrs{ExportedFilePath: utils.CDRE_DRYRUN, TotalRecords: 2, ExportedCGRIDs: []string{utils.Sha1("dsafdsaf", tm1.String()), utils.Sha1("adsafdsaf", tm2.String())}} if err := rater.Call("ApierV1.ExportCdrsToFile", req, &reply); err != nil { t.Error(err.Error()) @@ -1410,8 +1410,8 @@ func TestApierLocalGetCdrs(t *testing.T) { if !*testLocal { return } - var reply []*engine.ExternalCdr - req := utils.AttrGetCdrs{} + var reply []*engine.ExternalCDR + req := utils.AttrGetCdrs{MediationRunIds: []string{utils.MetaRaw}} if err := rater.Call("ApierV1.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { @@ -1424,18 +1424,19 @@ func TestApierLocalProcessCdr(t *testing.T) { return } var reply string - cdr := engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", + 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", + 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, } if err := rater.Call("CdrsV1.ProcessCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.ExternalCdr - req := utils.AttrGetCdrs{} + var cdrs []*engine.ExternalCDR + req := utils.AttrGetCdrs{MediationRunIds: []string{utils.MetaRaw}} if err := rater.Call("ApierV1.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 3 { @@ -1448,9 +1449,9 @@ func TestApierLocalSetDC(t *testing.T) { return } dcs1 := []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, } attrs := AttrSetDerivedChargers{Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: dcs1, Overwrite: true} @@ -1467,11 +1468,11 @@ func TestApierLocalGetDC(t *testing.T) { return } attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} - eDcs := utils.DerivedChargers{DestinationIds: utils.NewStringMap(), + eDcs := utils.DerivedChargers{DestinationIDs: utils.NewStringMap(), Chargers: []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, }} var dcs utils.DerivedChargers diff --git a/apier/v1/auth.go b/apier/v1/auth.go index 6d0367487..f462a14d7 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -32,11 +32,11 @@ func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float if err != nil { return utils.NewErrServerError(err) } - if usageRecord.TOR == "" { - usageRecord.TOR = utils.VOICE + if usageRecord.ToR == "" { + usageRecord.ToR = utils.VOICE } - if usageRecord.ReqType == "" { - usageRecord.ReqType = self.Config.DefaultReqType + if usageRecord.RequestType == "" { + usageRecord.RequestType = self.Config.DefaultReqType } if usageRecord.Direction == "" { usageRecord.Direction = utils.OUT diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go index 7335f4b28..0079a7ddc 100644 --- a/apier/v1/cdre.go +++ b/apier/v1/cdre.go @@ -120,7 +120,7 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E return fmt.Errorf("%s:FieldSeparator:%s", utils.ErrServerError.Error(), "Invalid") } } - exportDir := exportTemplate.ExportDir + exportDir := exportTemplate.ExportFolder if attr.ExportDir != nil && len(*attr.ExportDir) != 0 { exportDir = *attr.ExportDir } @@ -140,7 +140,7 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E if attr.DataUsageMultiplyFactor != nil && *attr.DataUsageMultiplyFactor != 0.0 { dataUsageMultiplyFactor = *attr.DataUsageMultiplyFactor } - smsUsageMultiplyFactor := exportTemplate.SmsUsageMultiplyFactor + smsUsageMultiplyFactor := exportTemplate.SMSUsageMultiplyFactor if attr.SmsUsageMultiplyFactor != nil && *attr.SmsUsageMultiplyFactor != 0.0 { smsUsageMultiplyFactor = *attr.SmsUsageMultiplyFactor } @@ -160,7 +160,7 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E if attr.RoundDecimals != nil { roundingDecimals = *attr.RoundDecimals } - maskDestId := exportTemplate.MaskDestId + maskDestId := exportTemplate.MaskDestinationID if attr.MaskDestinationId != nil && len(*attr.MaskDestinationId) != 0 { maskDestId = *attr.MaskDestinationId } @@ -168,11 +168,11 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E if attr.MaskLength != nil { maskLen = *attr.MaskLength } - cdrsFltr, err := attr.AsCdrsFilter(self.Config.DefaultTimezone) + cdrsFltr, err := attr.AsCDRsFilter(self.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } - cdrs, _, err := self.CdrDb.GetStoredCdrs(cdrsFltr) + cdrs, _, err := self.CdrDb.GetCDRs(cdrsFltr) if err != nil { return err } else if len(cdrs) == 0 { @@ -204,7 +204,7 @@ func (self *ApierV1) RemCdrs(attrs utils.AttrRemCdrs, reply *string) error { if len(attrs.CgrIds) == 0 { return fmt.Errorf("%s:CgrIds", utils.ErrMandatoryIeMissing.Error()) } - if err := self.CdrDb.RemStoredCdrs(attrs.CgrIds); err != nil { + if err := self.CdrDb.RemCDRs(attrs.CgrIds); err != nil { return utils.NewErrServerError(err) } *reply = "OK" diff --git a/apier/v1/cdrs.go b/apier/v1/cdrs.go index 909766a0a..c442826ee 100644 --- a/apier/v1/cdrs.go +++ b/apier/v1/cdrs.go @@ -31,7 +31,7 @@ func (apier *ApierV1) GetCallCostLog(attrs utils.AttrGetCallCost, reply *engine. if attrs.RunId == "" { attrs.RunId = utils.META_DEFAULT } - if cc, err := apier.CdrDb.GetCallCostLog(attrs.CgrId, "", attrs.RunId); err != nil { + if cc, err := apier.CdrDb.GetCallCostLog(attrs.CgrId, attrs.RunId); err != nil { return utils.NewErrServerError(err) } else if cc == nil { return utils.ErrNotFound @@ -42,18 +42,18 @@ func (apier *ApierV1) GetCallCostLog(attrs utils.AttrGetCallCost, reply *engine. } // Retrieves CDRs based on the filters -func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*engine.ExternalCdr) error { - cdrsFltr, err := attrs.AsCdrsFilter(apier.Config.DefaultTimezone) +func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*engine.ExternalCDR) error { + cdrsFltr, err := attrs.AsCDRsFilter(apier.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } - if cdrs, _, err := apier.CdrDb.GetStoredCdrs(cdrsFltr); err != nil { + if cdrs, _, err := apier.CdrDb.GetCDRs(cdrsFltr); err != nil { return utils.NewErrServerError(err) } else if len(cdrs) == 0 { - *reply = make([]*engine.ExternalCdr, 0) + *reply = make([]*engine.ExternalCDR, 0) } else { for _, cdr := range cdrs { - *reply = append(*reply, cdr.AsExternalCdr()) + *reply = append(*reply, cdr.AsExternalCDR()) } } return nil diff --git a/apier/v1/cdrstatsv1_local_test.go b/apier/v1/cdrstatsv1_local_test.go index 4a4d6d24c..b9a2b7354 100644 --- a/apier/v1/cdrstatsv1_local_test.go +++ b/apier/v1/cdrstatsv1_local_test.go @@ -111,31 +111,34 @@ func TestCDRStatsLclPostCdrs(t *testing.T) { return } httpClient := new(http.Client) - storedCdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + 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: "dsafdsaf", + OriginHost: "192.168.1.1", Source: "test", + RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), - AnswerTime: time.Now(), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan", + 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.StoredCdr{CgrId: utils.Sha1("dsafdsafb", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + &engine.CDR{CGRID: utils.Sha1("dsafdsafb", 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: "+4986517174963", SetupTime: time.Now(), - AnswerTime: time.Now(), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(5) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan", + 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.StoredCdr{CgrId: utils.Sha1("dsafdsafc", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + &engine.CDR{CGRID: utils.Sha1("dsafdsafc", 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: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(), - MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(30) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan", + RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(30) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsafd", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + &engine.CDR{CGRID: utils.Sha1("dsafdsafd", 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: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Time{}, - MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan", + RunID: utils.DEFAULT_RUNID, + Usage: time.Duration(0) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, }, } for _, storedCdr := range storedCdrs { diff --git a/apier/v1/cdrsv1.go b/apier/v1/cdrsv1.go index c0913766a..21b24ffa0 100644 --- a/apier/v1/cdrsv1.go +++ b/apier/v1/cdrsv1.go @@ -19,8 +19,6 @@ along with this program. If not, see package v1 import ( - "time" - "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" ) @@ -31,7 +29,7 @@ type CdrsV1 struct { } // Designed for CGR internal usage -func (self *CdrsV1) ProcessCdr(cdr *engine.StoredCdr, reply *string) error { +func (self *CdrsV1) ProcessCdr(cdr *engine.CDR, reply *string) error { if err := self.CdrSrv.LocalProcessCdr(cdr); err != nil { return utils.NewErrServerError(err) } @@ -40,7 +38,7 @@ func (self *CdrsV1) ProcessCdr(cdr *engine.StoredCdr, reply *string) error { } // Designed for external programs feeding CDRs to CGRateS -func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCdr, reply *string) error { +func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCDR, reply *string) error { if err := self.CdrSrv.ProcessExternalCdr(cdr); err != nil { return utils.NewErrServerError(err) } @@ -50,23 +48,11 @@ func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCdr, reply *string) e // Remotely start mediation with specific runid, runs asynchronously, it's status will be displayed in syslog func (self *CdrsV1) RateCdrs(attrs utils.AttrRateCdrs, reply *string) error { - var tStart, tEnd time.Time - var err error - if len(attrs.TimeStart) != 0 { - if tStart, err = utils.ParseTimeDetectLayout(attrs.TimeStart, self.CdrSrv.Timezone()); err != nil { - return err - } + cdrsFltr, err := attrs.AsCDRsFilter(self.CdrSrv.Timezone()) + if err != nil { + return utils.NewErrServerError(err) } - if len(attrs.TimeEnd) != 0 { - if tEnd, err = utils.ParseTimeDetectLayout(attrs.TimeEnd, self.CdrSrv.Timezone()); err != nil { - return err - } - } - //RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes []string, - //orderIdStart, orderIdEnd int64, timeStart, timeEnd time.Time, rerateErrors, rerateRated bool) - if err := self.CdrSrv.RateCdrs(attrs.CgrIds, attrs.MediationRunIds, attrs.TORs, attrs.CdrHosts, attrs.CdrSources, attrs.ReqTypes, attrs.Directions, - attrs.Tenants, attrs.Categories, attrs.Accounts, attrs.Subjects, attrs.DestinationPrefixes, attrs.RatedAccounts, attrs.RatedSubjects, - attrs.OrderIdStart, attrs.OrderIdEnd, tStart, tEnd, attrs.RerateErrors, attrs.RerateRated, attrs.SendToStats); err != nil { + if err := self.CdrSrv.RateCDRs(cdrsFltr, attrs.SendToStats); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK diff --git a/apier/v1/debit.go b/apier/v1/debit.go index c049ac3f3..bd9f53209 100644 --- a/apier/v1/debit.go +++ b/apier/v1/debit.go @@ -32,11 +32,11 @@ func (self *ApierV1) DebitUsage(usageRecord engine.UsageRecord, reply *string) e *reply = err.Error() return err } - if usageRecord.TOR == "" { - usageRecord.TOR = utils.VOICE + if usageRecord.ToR == "" { + usageRecord.ToR = utils.VOICE } - if usageRecord.ReqType == "" { - usageRecord.ReqType = self.Config.DefaultReqType + if usageRecord.RequestType == "" { + usageRecord.RequestType = self.Config.DefaultReqType } if usageRecord.Direction == "" { usageRecord.Direction = utils.OUT diff --git a/apier/v1/derivedcharging.go b/apier/v1/derivedcharging.go index 5e74fb00d..0c573f797 100644 --- a/apier/v1/derivedcharging.go +++ b/apier/v1/derivedcharging.go @@ -78,7 +78,7 @@ func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *str } } dstIds := strings.Split(attrs.DestinationIds, utils.INFIELD_SEP) - dcs := &utils.DerivedChargers{DestinationIds: utils.NewStringMap(dstIds...), Chargers: attrs.DerivedChargers} + dcs := &utils.DerivedChargers{DestinationIDs: utils.NewStringMap(dstIds...), Chargers: attrs.DerivedChargers} if err := self.RatingDb.SetDerivedChargers(dcKey, dcs); err != nil { return utils.NewErrServerError(err) } diff --git a/apier/v1/derivedcharging_test.go b/apier/v1/derivedcharging_test.go index dfc2df07c..87e3d847f 100644 --- a/apier/v1/derivedcharging_test.go +++ b/apier/v1/derivedcharging_test.go @@ -49,9 +49,9 @@ func TestGetEmptyDC(t *testing.T) { func TestSetDC(t *testing.T) { dcs1 := []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, } attrs := AttrSetDerivedChargers{Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: dcs1} @@ -65,18 +65,18 @@ func TestSetDC(t *testing.T) { func TestGetDC(t *testing.T) { attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} - eDcs := utils.DerivedChargers{DestinationIds: utils.NewStringMap(), + eDcs := utils.DerivedChargers{DestinationIDs: utils.NewStringMap(), Chargers: []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, }} var dcs utils.DerivedChargers if err := apierDcT.GetDerivedChargers(attrs, &dcs); err != nil { t.Error("Unexpected error", err.Error()) } else if !reflect.DeepEqual(dcs, eDcs) { - t.Errorf("Expecting: %v, received: %v", eDcs.DestinationIds, dcs.DestinationIds) + t.Errorf("Expecting: %v, received: %v", eDcs.DestinationIDs, dcs.DestinationIDs) } } diff --git a/apier/v2/cdre.go b/apier/v2/cdre.go index dbeaee933..3bb7b0697 100644 --- a/apier/v2/cdre.go +++ b/apier/v2/cdre.go @@ -56,19 +56,19 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut return fmt.Errorf("%s:FieldSeparator:%s", utils.ErrServerError, "Invalid") } } - exportDir := exportTemplate.ExportDir - if attr.ExportDir != nil && len(*attr.ExportDir) != 0 { - exportDir = *attr.ExportDir + ExportFolder := exportTemplate.ExportFolder + if attr.ExportFolder != nil && len(*attr.ExportFolder) != 0 { + ExportFolder = *attr.ExportFolder } - exportId := strconv.FormatInt(time.Now().Unix(), 10) - if attr.ExportId != nil && len(*attr.ExportId) != 0 { - exportId = *attr.ExportId + ExportID := strconv.FormatInt(time.Now().Unix(), 10) + if attr.ExportID != nil && len(*attr.ExportID) != 0 { + ExportID = *attr.ExportID } - fileName := fmt.Sprintf("cdre_%s.%s", exportId, cdrFormat) + fileName := fmt.Sprintf("cdre_%s.%s", ExportID, cdrFormat) if attr.ExportFileName != nil && len(*attr.ExportFileName) != 0 { fileName = *attr.ExportFileName } - filePath := path.Join(exportDir, fileName) + filePath := path.Join(ExportFolder, fileName) if cdrFormat == utils.DRYRUN { filePath = utils.DRYRUN } @@ -76,9 +76,9 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut if attr.DataUsageMultiplyFactor != nil && *attr.DataUsageMultiplyFactor != 0.0 { dataUsageMultiplyFactor = *attr.DataUsageMultiplyFactor } - smsUsageMultiplyFactor := exportTemplate.SmsUsageMultiplyFactor - if attr.SmsUsageMultiplyFactor != nil && *attr.SmsUsageMultiplyFactor != 0.0 { - smsUsageMultiplyFactor = *attr.SmsUsageMultiplyFactor + SMSUsageMultiplyFactor := exportTemplate.SMSUsageMultiplyFactor + if attr.SMSUsageMultiplyFactor != nil && *attr.SMSUsageMultiplyFactor != 0.0 { + SMSUsageMultiplyFactor = *attr.SMSUsageMultiplyFactor } genericUsageMultiplyFactor := exportTemplate.GenericUsageMultiplyFactor if attr.GenericUsageMultiplyFactor != nil && *attr.GenericUsageMultiplyFactor != 0.0 { @@ -96,26 +96,26 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut if attr.RoundDecimals != nil { roundingDecimals = *attr.RoundDecimals } - maskDestId := exportTemplate.MaskDestId - if attr.MaskDestinationId != nil && len(*attr.MaskDestinationId) != 0 { - maskDestId = *attr.MaskDestinationId + maskDestId := exportTemplate.MaskDestinationID + if attr.MaskDestinationID != nil && len(*attr.MaskDestinationID) != 0 { + maskDestId = *attr.MaskDestinationID } maskLen := exportTemplate.MaskLength if attr.MaskLength != nil { maskLen = *attr.MaskLength } - cdrsFltr, err := attr.RpcCdrsFilter.AsCdrsFilter(self.Config.DefaultTimezone) + cdrsFltr, err := attr.RPCCDRsFilter.AsCDRsFilter(self.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } - cdrs, _, err := self.CdrDb.GetStoredCdrs(cdrsFltr) + cdrs, _, err := self.CdrDb.GetCDRs(cdrsFltr) if err != nil { return err } else if len(cdrs) == 0 { *reply = utils.ExportedFileCdrs{ExportedFilePath: ""} return nil } - cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, exportId, dataUsageMultiplyFactor, smsUsageMultiplyFactor, genericUsageMultiplyFactor, + cdrexp, err := cdre.NewCdrExporter(cdrs, self.CdrDb, exportTemplate, cdrFormat, fieldSep, ExportID, dataUsageMultiplyFactor, SMSUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor, costShiftDigits, roundingDecimals, self.Config.RoundingDecimals, maskDestId, maskLen, self.Config.HttpSkipTlsVerify, self.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) @@ -128,7 +128,7 @@ func (self *ApierV2) ExportCdrsToFile(attr utils.AttrExportCdrsToFile, reply *ut return utils.NewErrServerError(err) } *reply = utils.ExportedFileCdrs{ExportedFilePath: filePath, TotalRecords: len(cdrs), TotalCost: cdrexp.TotalCost(), FirstOrderId: cdrexp.FirstOrderId(), LastOrderId: cdrexp.LastOrderId()} - if !attr.SuppressCgrIds { + if !attr.Verbose { reply.ExportedCgrIds = cdrexp.PositiveExports() reply.UnexportedCgrIds = cdrexp.NegativeExports() } diff --git a/apier/v2/cdrs.go b/apier/v2/cdrs.go index b6fa0f5c8..99d7bb030 100644 --- a/apier/v2/cdrs.go +++ b/apier/v2/cdrs.go @@ -26,30 +26,30 @@ import ( ) // Retrieves CDRs based on the filters -func (apier *ApierV2) GetCdrs(attrs utils.RpcCdrsFilter, reply *[]*engine.ExternalCdr) error { - cdrsFltr, err := attrs.AsCdrsFilter(apier.Config.DefaultTimezone) +func (apier *ApierV2) GetCdrs(attrs utils.RPCCDRsFilter, reply *[]*engine.ExternalCDR) error { + cdrsFltr, err := attrs.AsCDRsFilter(apier.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } - if cdrs, _, err := apier.CdrDb.GetStoredCdrs(cdrsFltr); err != nil { + if cdrs, _, err := apier.CdrDb.GetCDRs(cdrsFltr); err != nil { return utils.NewErrServerError(err) } else if len(cdrs) == 0 { - *reply = make([]*engine.ExternalCdr, 0) + *reply = make([]*engine.ExternalCDR, 0) } else { for _, cdr := range cdrs { - *reply = append(*reply, cdr.AsExternalCdr()) + *reply = append(*reply, cdr.AsExternalCDR()) } } return nil } -func (apier *ApierV2) CountCdrs(attrs utils.RpcCdrsFilter, reply *int64) error { - cdrsFltr, err := attrs.AsCdrsFilter(apier.Config.DefaultTimezone) +func (apier *ApierV2) CountCdrs(attrs utils.RPCCDRsFilter, reply *int64) error { + cdrsFltr, err := attrs.AsCDRsFilter(apier.Config.DefaultTimezone) if err != nil { return utils.NewErrServerError(err) } cdrsFltr.Count = true - if _, count, err := apier.CdrDb.GetStoredCdrs(cdrsFltr); err != nil { + if _, count, err := apier.CdrDb.GetCDRs(cdrsFltr); err != nil { return utils.NewErrServerError(err) } else { *reply = count diff --git a/apier/v2/cdrs_mongo_local_test.go b/apier/v2/cdrs_mongo_local_test.go index 8ce6186ea..a0e248015 100644 --- a/apier/v2/cdrs_mongo_local_test.go +++ b/apier/v2/cdrs_mongo_local_test.go @@ -68,18 +68,18 @@ func TestV2CdrsMongoInjectUnratedCdr(t *testing.T) { if !*testLocal { return } - mysqlDb, err := engine.NewMongoStorage(cdrsMongoCfg.StorDBHost, cdrsMongoCfg.StorDBPort, cdrsMongoCfg.StorDBName, cdrsMongoCfg.StorDBUser, cdrsMongoCfg.StorDBPass) + mongoDb, err := engine.NewMongoStorage(cdrsMongoCfg.StorDBHost, cdrsMongoCfg.StorDBPort, cdrsMongoCfg.StorDBName, cdrsMongoCfg.StorDBUser, cdrsMongoCfg.StorDBPass) if err != nil { t.Error("Error on opening database connection: ", err) return } - strCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, + 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", - SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), + 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"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - if err := mysqlDb.SetCdr(strCdr1); err != nil { + Cost: -1} + if err := mongoDb.SetCDR(strCdr1, false); err != nil { t.Error(err.Error()) } } @@ -105,90 +105,85 @@ func TestV2CdrsMongoRpcConn(t *testing.T) { } } -// Insert some CDRs -func TestV2CdrsMongoProcessCdr(t *testing.T) { +func TestV2CdrsMongoProcessCdrRated(t *testing.T) { if !*testLocal { return } + 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", + 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"}, + Cost: 1.01, CostSource: "TestV2CdrsMongoProcessCdrRated", Rated: true, + } var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, - }, - &engine.StoredCdr{CgrId: utils.Sha1("abcdeftg", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, + if err := cdrsMongoRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) } - for _, cdr := range cdrs { - if err := cdrsMongoRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if reply != utils.OK { - t.Error("Unexpected reply received: ", reply) - } +} + +func TestV2CdrsMongoProcessCdrRaw(t *testing.T) { + if !*testLocal { + return } + 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", + 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"}, + } + var reply string + if err := cdrsMongoRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) } func TestV2CdrsMongoGetCdrs(t *testing.T) { if !*testLocal { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{NotCdrSources: []string{"CDRS"}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{} if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 4 { - for _, cdr := range reply { - t.Logf("CDR: %s %s %s", cdr.CgrId, cdr.CdrSource, cdr.MediationRunId) - } + } else if len(reply) != 4 { // 1 injected, 1 rated, 1 *raw and it's pair in *default run t.Error("Unexpected number of CDRs returned: ", len(reply)) } - // CDRs with errors - req = utils.RpcCdrsFilter{NotCdrSources: []string{"CDRS"}, MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} + // CDRs with rating errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 2 { + } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", reply) } // CDRs Rated - req = utils.RpcCdrsFilter{NotCdrSources: []string{"CDRS"}, MinCost: utils.Float64Pointer(-1.0)} - if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 4 { - for _, cdr := range reply { - t.Logf("CDR: %s %s %s %f", cdr.CgrId, cdr.CdrSource, cdr.MediationRunId, cdr.Cost) - } - t.Error("Unexpected number of CDRs returned: ", reply) - } - // CDRs non rated OR SkipRated - req = utils.RpcCdrsFilter{NotCdrSources: []string{"CDRS"}, MaxCost: utils.Float64Pointer(-1.0)} - if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 0 { - for _, cdr := range reply { - t.Logf("CDR: %s %s %s %f", cdr.CgrId, cdr.CdrSource, cdr.MediationRunId, cdr.Cost) - } - t.Error("Unexpected number of CDRs returned: ", reply) - } - // Skip Errors - req = utils.RpcCdrsFilter{NotCdrSources: []string{"CDRS"}, MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}} if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { - for _, cdr := range reply { - t.Logf("CDR: %s %s %s %f", cdr.CgrId, cdr.CdrSource, cdr.MediationRunId, cdr.Cost) - } + t.Error("Unexpected number of CDRs returned: ", reply) + } + // Raw CDRs + req = utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}} + if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 2 { + t.Error("Unexpected number of CDRs returned: ", reply) + } + // Skip Errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", reply) } } @@ -198,7 +193,7 @@ func TestV2CdrsMongoCountCdrs(t *testing.T) { return } var reply int64 - req := utils.AttrGetCdrs{CdrSources: []string{"test", "UNKNOWN"}} + req := utils.AttrGetCdrs{} if err := cdrsMongoRpc.Call("ApierV2.CountCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != 4 { @@ -206,30 +201,30 @@ func TestV2CdrsMongoCountCdrs(t *testing.T) { } } -// Test Prepaid CDRs without previous costs being calculated +// Make sure *prepaid does not block until finding previous costs func TestV2CdrsMongoProcessPrepaidCdr(t *testing.T) { if !*testLocal { return } var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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", + 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.StoredCdr{CgrId: utils.Sha1("abcdeftg2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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", + 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, - RatedAccount: "dan", RatedSubject: "dans", }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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", + 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, - RatedAccount: "dan", RatedSubject: "dans", }, } tStart := time.Now() @@ -245,6 +240,73 @@ func TestV2CdrsMongoProcessPrepaidCdr(t *testing.T) { } } +func TestV2CdrsMongoRateWithoutTP(t *testing.T) { + if !*testLocal { + return + } + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + // Rate the injected CDR, should not rate it since we have no TP loaded + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} + var reply string + if err := cdrsMongoRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} + if err := cdrsMongoRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { // Injected CDR did not have a charging run + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if cdrs[0].Cost != -1 { + t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) + } + } +} + +func TestV2CdrsMongoLoadTariffPlanFromFolder(t *testing.T) { + if !*testLocal { + return + } + var loadInst engine.LoadInstance + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")} + if err := cdrsMongoRpc.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &loadInst); err != nil { + t.Error(err) + } else if loadInst.LoadId == "" { + t.Error("Empty loadId received, loadInstance: ", loadInst) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups +} + +func TestV2CdrsMongoRateWithTP(t *testing.T) { + if !*testLocal { + return + } + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} + var reply string + if err := cdrsMongoRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} + if err := cdrsMongoRpc.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].Cost != 0.3 { + t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) + } + } +} + func TestV2CdrsMongoKillEngine(t *testing.T) { if !*testLocal { return diff --git a/apier/v2/cdrs_mysql_local_test.go b/apier/v2/cdrs_mysql_local_test.go index 0cadbe1d4..bbbed922e 100644 --- a/apier/v2/cdrs_mysql_local_test.go +++ b/apier/v2/cdrs_mysql_local_test.go @@ -39,7 +39,7 @@ var cdrsCfgPath string var cdrsCfg *config.CGRConfig var cdrsRpc *rpc.Client -func TestV2CdrsMysqlInitConfig(t *testing.T) { +func TestV2CDRsMySQLInitConfig(t *testing.T) { if !*testLocal { return } @@ -50,7 +50,7 @@ func TestV2CdrsMysqlInitConfig(t *testing.T) { } } -func TestV2CdrsMysqlInitDataDb(t *testing.T) { +func TestV2CDRsMySQLInitDataDb(t *testing.T) { if !*testLocal { return } @@ -60,7 +60,7 @@ func TestV2CdrsMysqlInitDataDb(t *testing.T) { } // InitDb so we can rely on count -func TestV2CdrsMysqlInitCdrDb(t *testing.T) { +func TestV2CDRsMySQLInitCdrDb(t *testing.T) { if !*testLocal { return } @@ -69,7 +69,7 @@ func TestV2CdrsMysqlInitCdrDb(t *testing.T) { } } -func TestV2CdrsMysqlInjectUnratedCdr(t *testing.T) { +func TestV2CDRsMySQLInjectUnratedCdr(t *testing.T) { if !*testLocal { return } @@ -79,18 +79,18 @@ func TestV2CdrsMysqlInjectUnratedCdr(t *testing.T) { t.Error("Error on opening database connection: ", err) return } - strCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, + 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: "TestV2CDRsMySQLInjectUnratedCdr", RequestType: utils.META_RATED, Direction: "*out", 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"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - if err := mysqlDb.SetCdr(strCdr1); err != nil { + Cost: -1} + if err := mysqlDb.SetCDR(strCdr1, false); err != nil { t.Error(err.Error()) } } -func TestV2CdrsMysqlStartEngine(t *testing.T) { +func TestV2CDRsMySQLStartEngine(t *testing.T) { if !*testLocal { return } @@ -100,7 +100,7 @@ func TestV2CdrsMysqlStartEngine(t *testing.T) { } // Connect rpc client to rater -func TestV2CdrsMysqlRpcConn(t *testing.T) { +func TestV2CDRsMySQLRpcConn(t *testing.T) { if !*testLocal { return } @@ -111,83 +111,90 @@ func TestV2CdrsMysqlRpcConn(t *testing.T) { } } -// Insert some CDRs -func TestV2CdrsMysqlProcessCdr(t *testing.T) { +func TestV2CDRsMySQLProcessCdrRated(t *testing.T) { if !*testLocal { return } - var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, - }, - &engine.StoredCdr{CgrId: utils.Sha1("abcdeftg", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, + 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: "TestV2CDRsMySQLProcessCdrRated", RequestType: utils.META_RATED, Direction: "*out", 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"}, + Cost: 1.01, CostSource: "TestV2CDRsMySQLProcessCdrRated", Rated: true, } - for _, cdr := range cdrs { - if err := cdrsRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if reply != utils.OK { - t.Error("Unexpected reply received: ", reply) - } + var reply string + if err := cdrsRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) } } -func TestV2CdrsMysqlGetCdrs(t *testing.T) { +func TestV2CDRsMySQLProcessCdrRaw(t *testing.T) { if !*testLocal { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{} + 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: "TestV2CDRsMySQLProcessCdrRaw", RequestType: utils.META_RATED, Direction: "*out", 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"}, + } + var reply string + if err := cdrsRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) +} + +func TestV2CDRsMySQLGetCdrs(t *testing.T) { + if !*testLocal { + return + } + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{} if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 4 { + } else if len(reply) != 4 { // 1 injected, 1 rated, 1 *raw and it's pair in *default run t.Error("Unexpected number of CDRs returned: ", len(reply)) } - // CDRs with errors - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} - if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 2 { - t.Error("Unexpected number of CDRs returned: ", reply) - } - // CDRs Rated - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0)} - if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 3 { - t.Error("Unexpected number of CDRs returned: ", reply) - } - // CDRs non rated OR SkipRated - req = utils.RpcCdrsFilter{MaxCost: utils.Float64Pointer(-1.0)} + // CDRs with rating errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", reply) } - // Skip Errors - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + // CDRs Rated + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}} if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", reply) } + // Raw CDRs + req = utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}} + if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 2 { + t.Error("Unexpected number of CDRs returned: ", reply) + } + // Skip Errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + if err := cdrsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 1 { + t.Error("Unexpected number of CDRs returned: ", reply) + } } -func TestV2CdrsMysqlCountCdrs(t *testing.T) { +func TestV2CDRsMySQLCountCdrs(t *testing.T) { if !*testLocal { return } @@ -200,30 +207,27 @@ func TestV2CdrsMysqlCountCdrs(t *testing.T) { } } -// Test Prepaid CDRs without previous costs being calculated -func TestV2CdrsMysqlProcessPrepaidCdr(t *testing.T) { +// Make sure *prepaid does not block until finding previous costs +func TestV2CDRsMySQLProcessPrepaidCdr(t *testing.T) { if !*testLocal { return } var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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: "TestV2CDRsMySQLProcessPrepaidCdr1", RequestType: utils.META_PREPAID, 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, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, }, - &engine.StoredCdr{CgrId: utils.Sha1("abcdeftg2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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: "TestV2CDRsMySQLProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Direction: "*out", 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, - RatedAccount: "dan", RatedSubject: "dans", }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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: "TestV2CDRsMySQLProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Direction: "*out", 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, - RatedAccount: "dan", RatedSubject: "dans", }, } tStart := time.Now() @@ -239,25 +243,25 @@ func TestV2CdrsMysqlProcessPrepaidCdr(t *testing.T) { } } -func TestV2CdrsMysqlRateWithoutTP(t *testing.T) { +func TestV2CDRsMySQLRateWithoutTP(t *testing.T) { if !*testLocal { return } - rawCdrCgrId := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) // Rate the injected CDR, should not rate it since we have no TP loaded - attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCgrId}} + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} var reply string if err := cdrsRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{CgrIds: []string{rawCdrCgrId}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} if err := cdrsRpc.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(reply)) + } else if len(cdrs) != 1 { // Injected CDR did not have a charging run + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { if cdrs[0].Cost != -1 { t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) @@ -265,7 +269,7 @@ func TestV2CdrsMysqlRateWithoutTP(t *testing.T) { } } -func TestV2CdrsMysqloadTariffPlanFromFolder(t *testing.T) { +func TestV2CDRsMySQLLoadTariffPlanFromFolder(t *testing.T) { if !*testLocal { return } @@ -279,24 +283,24 @@ func TestV2CdrsMysqloadTariffPlanFromFolder(t *testing.T) { time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups } -func TestV2CdrsMysqlRateWithTP(t *testing.T) { +func TestV2CDRsMySQLRateWithTP(t *testing.T) { if !*testLocal { return } - rawCdrCgrId := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) - attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCgrId}} + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} var reply string if err := cdrsRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{CgrIds: []string{rawCdrCgrId}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} if err := cdrsRpc.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(reply)) + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { if cdrs[0].Cost != 0.3 { t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) @@ -306,21 +310,21 @@ func TestV2CdrsMysqlRateWithTP(t *testing.T) { /* // Benchmark speed of processing 1000 CDRs -func TestV2CdrsMysqlProcessRatedExternalCdrBenchmark(t *testing.T) { +func TestV2CDRsMySQLProcessRatedExternalCdrBenchmark(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "benchratedcdr", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "benchratedcdr", 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", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "15", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "15", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string tStart := time.Now() nrCdrs := 1000 for i := 0; i < nrCdrs; i++ { - cdr.AccId = "benchratedcdr" + strconv.Itoa(i) + cdr.OriginID = "benchratedcdr" + strconv.Itoa(i) if err := cdrsRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -333,7 +337,7 @@ func TestV2CdrsMysqlProcessRatedExternalCdrBenchmark(t *testing.T) { } // Benchmark speed of re-rating 1000 CDRs -func TestV2CdrsMysqlReRateWithTPBenchmark(t *testing.T) { +func TestV2CDRsMySQLReRateWithTPBenchmark(t *testing.T) { if !*testLocal { return } @@ -355,21 +359,21 @@ func TestV2CdrsMysqlReRateWithTPBenchmark(t *testing.T) { } // Benchmark speed of processing 1000 postpaid CDRs -func TestV2CdrsMysqlProcessPostpaidExternalCdrBenchmark(t *testing.T) { +func TestV2CDRsMySQLProcessPostpaidExternalCdrBenchmark(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "benchpostpaidcdr", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "benchpostpaidcdr", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "15", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "15", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string tStart := time.Now() nrCdrs := 1000 for i := 0; i < nrCdrs; i++ { - cdr.AccId = "benchpostpaidcdr" + strconv.Itoa(i) + cdr.OriginID = "benchpostpaidcdr" + strconv.Itoa(i) if err := cdrsRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -382,7 +386,7 @@ func TestV2CdrsMysqlProcessPostpaidExternalCdrBenchmark(t *testing.T) { } */ -func TestV2CdrsMysqlKillEngine(t *testing.T) { +func TestV2CDRsMySQLKillEngine(t *testing.T) { if !*testLocal { return } diff --git a/apier/v2/cdrs_psql_local_test.go b/apier/v2/cdrs_psql_local_test.go index b02732245..03d387c01 100644 --- a/apier/v2/cdrs_psql_local_test.go +++ b/apier/v2/cdrs_psql_local_test.go @@ -36,7 +36,7 @@ var cdrsPsqlCfg *config.CGRConfig var cdrsPsqlRpc *rpc.Client var cmdEngineCdrPsql *exec.Cmd -func TestV2CdrsPsqlInitConfig(t *testing.T) { +func TestV2CDRsPSQLInitConfig(t *testing.T) { if !*testLocal { return } @@ -47,7 +47,7 @@ func TestV2CdrsPsqlInitConfig(t *testing.T) { } } -func TestV2CdrsPsqlInitDataDb(t *testing.T) { +func TestV2CDRsPSQLInitDataDb(t *testing.T) { if !*testLocal { return } @@ -57,7 +57,7 @@ func TestV2CdrsPsqlInitDataDb(t *testing.T) { } // InitDb so we can rely on count -func TestV2CdrsPsqlInitCdrDb(t *testing.T) { +func TestV2CDRsPSQLInitCdrDb(t *testing.T) { if !*testLocal { return } @@ -66,7 +66,7 @@ func TestV2CdrsPsqlInitCdrDb(t *testing.T) { } } -func TestV2CdrsPsqlInjectUnratedCdr(t *testing.T) { +func TestV2CDRsPSQLInjectUnratedCdr(t *testing.T) { if !*testLocal { return } @@ -76,29 +76,28 @@ func TestV2CdrsPsqlInjectUnratedCdr(t *testing.T) { t.Error("Error on opening database connection: ", err) return } - strCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, + 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: "TestV2CDRsPSQLInjectUnratedCdr", RequestType: utils.META_RATED, Direction: "*out", 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"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - if err := psqlDb.SetCdr(strCdr1); err != nil { + Cost: -1} + if err := psqlDb.SetCDR(strCdr1, false); err != nil { t.Error(err.Error()) } } -func TestV2CdrsPsqlStartEngine(t *testing.T) { +func TestV2CDRsPSQLStartEngine(t *testing.T) { if !*testLocal { return } - var err error - if cmdEngineCdrPsql, err = engine.StartEngine(cdrsPsqlCfgPath, *waitRater); err != nil { + if _, err := engine.StopStartEngine(cdrsPsqlCfgPath, *waitRater); err != nil { t.Fatal(err) } } // Connect rpc client to rater -func TestV2CdrsPsqlPsqlRpcConn(t *testing.T) { +func TestV2CDRsPSQLRpcConn(t *testing.T) { if !*testLocal { return } @@ -109,83 +108,90 @@ func TestV2CdrsPsqlPsqlRpcConn(t *testing.T) { } } -// Insert some CDRs -func TestV2CdrsPsqlProcessCdr(t *testing.T) { +func TestV2CDRsPSQLProcessCdrRated(t *testing.T) { if !*testLocal { return } - var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, - }, - &engine.StoredCdr{CgrId: utils.Sha1("abcdeftg", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", - }, + 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: "TestV2CDRsPSQLProcessCdrRated", RequestType: utils.META_RATED, Direction: "*out", 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"}, + Cost: 1.01, CostSource: "TestV2CDRsPSQLProcessCdrRated", Rated: true, } - for _, cdr := range cdrs { - if err := cdrsPsqlRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if reply != utils.OK { - t.Error("Unexpected reply received: ", reply) - } + var reply string + if err := cdrsPsqlRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) } } -func TestV2CdrsPsqlGetCdrs(t *testing.T) { +func TestV2CDRsPSQLProcessCdrRaw(t *testing.T) { if !*testLocal { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{} + 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: "TestV2CDRsPSQLProcessCdrRaw", RequestType: utils.META_RATED, Direction: "*out", 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"}, + } + var reply string + if err := cdrsPsqlRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received: ", reply) + } + time.Sleep(time.Duration(*waitRater) * time.Millisecond) +} + +func TestV2CDRsPSQLGetCdrs(t *testing.T) { + if !*testLocal { + return + } + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{} if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 4 { + } else if len(reply) != 4 { // 1 injected, 1 rated, 1 *raw and it's pair in *default run t.Error("Unexpected number of CDRs returned: ", len(reply)) } - // CDRs with errors - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} - if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 2 { - t.Error("Unexpected number of CDRs returned: ", reply) - } - // CDRs Rated - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(-1.0)} - if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if len(reply) != 3 { - t.Error("Unexpected number of CDRs returned: ", reply) - } - // CDRs non rated OR SkipRated - req = utils.RpcCdrsFilter{MaxCost: utils.Float64Pointer(-1.0)} + // CDRs with rating errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(-1.0), MaxCost: utils.Float64Pointer(0.0)} if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", reply) } - // Skip Errors - req = utils.RpcCdrsFilter{MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + // CDRs Rated + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}} if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", reply) } + // Raw CDRs + req = utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}} + if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 2 { + t.Error("Unexpected number of CDRs returned: ", reply) + } + // Skip Errors + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, MinCost: utils.Float64Pointer(0.0), MaxCost: utils.Float64Pointer(-1.0)} + if err := cdrsPsqlRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 1 { + t.Error("Unexpected number of CDRs returned: ", reply) + } } -func TestV2CdrsPsqlCountCdrs(t *testing.T) { +func TestV2CDRsPSQLCountCdrs(t *testing.T) { if !*testLocal { return } @@ -198,30 +204,27 @@ func TestV2CdrsPsqlCountCdrs(t *testing.T) { } } -// Test Prepaid CDRs without previous costs being calculated -func TestV2CdrsPsqlProcessPrepaidCdr(t *testing.T) { +// Make sure *prepaid does not block until finding previous costs +func TestV2CDRsPSQLProcessPrepaidCdr(t *testing.T) { if !*testLocal { return } var reply string - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, - RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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: "TestV2CDRsPSQLProcessPrepaidCdr1", RequestType: utils.META_PREPAID, 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, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, Rated: true, }, - &engine.StoredCdr{CgrId: utils.Sha1("abcdeftg2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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: "TestV2CDRsPSQLProcessPrepaidCdr2", RequestType: utils.META_PREPAID, Direction: "*out", 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, - RatedAccount: "dan", RatedSubject: "dans", }, - &engine.StoredCdr{CgrId: utils.Sha1("aererfddf2", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", 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), MediationRunId: utils.DEFAULT_RUNID, + &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: "TestV2CDRsPSQLProcessPrepaidCdr3", RequestType: utils.META_PREPAID, Direction: "*out", 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, - RatedAccount: "dan", RatedSubject: "dans", }, } tStart := time.Now() @@ -237,25 +240,25 @@ func TestV2CdrsPsqlProcessPrepaidCdr(t *testing.T) { } } -func TestV2CdrsPsqlRateWithoutTP(t *testing.T) { +func TestV2CDRsPSQLRateWithoutTP(t *testing.T) { if !*testLocal { return } - rawCdrCgrId := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) // Rate the injected CDR, should not rate it since we have no TP loaded - attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCgrId}} + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} var reply string if err := cdrsPsqlRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{CgrIds: []string{rawCdrCgrId}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} if err := cdrsPsqlRpc.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(reply)) + } else if len(cdrs) != 1 { // Injected CDR did not have a charging run + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { if cdrs[0].Cost != -1 { t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) @@ -263,7 +266,7 @@ func TestV2CdrsPsqlRateWithoutTP(t *testing.T) { } } -func TestV2CdrsPsqlLoadTariffPlanFromFolder(t *testing.T) { +func TestV2CDRsPSQLLoadTariffPlanFromFolder(t *testing.T) { if !*testLocal { return } @@ -277,24 +280,24 @@ func TestV2CdrsPsqlLoadTariffPlanFromFolder(t *testing.T) { time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups } -func TestV2CdrsPsqlRateWithTP(t *testing.T) { +func TestV2CDRsPSQLRateWithTP(t *testing.T) { if !*testLocal { return } - rawCdrCgrId := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) - attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCgrId}} + rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String()) + attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}} var reply string if err := cdrsPsqlRpc.Call("CdrsV2.RateCdrs", attrs, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{CgrIds: []string{rawCdrCgrId}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{CGRIDs: []string{rawCdrCGRID}, RunIDs: []string{utils.META_DEFAULT}} if err := cdrsPsqlRpc.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(reply)) + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { if cdrs[0].Cost != 0.3 { t.Errorf("Unexpected CDR returned: %+v", cdrs[0]) @@ -304,21 +307,21 @@ func TestV2CdrsPsqlRateWithTP(t *testing.T) { /* // Benchmark speed of processing 1000 CDRs -func TestV2CdrsPsqlProcessRatedExternalCdrBenchmark(t *testing.T) { +func TestV2CDRsPSQLProcessRatedExternalCdrBenchmark(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "benchratedcdr", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "benchratedcdr", 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", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "15", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "15", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string tStart := time.Now() nrCdrs := 1000 for i := 0; i < nrCdrs; i++ { - cdr.AccId = "benchratedcdr" + strconv.Itoa(i) + cdr.OriginID = "benchratedcdr" + strconv.Itoa(i) if err := cdrsPsqlRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -331,7 +334,7 @@ func TestV2CdrsPsqlProcessRatedExternalCdrBenchmark(t *testing.T) { } // Benchmark speed of re-rating 1000 CDRs -func TestV2CdrsPsqlReRateWithTPBenchmark(t *testing.T) { +func TestV2CDRsPSQLReRateWithTPBenchmark(t *testing.T) { if !*testLocal { return } @@ -353,21 +356,21 @@ func TestV2CdrsPsqlReRateWithTPBenchmark(t *testing.T) { } // Benchmark speed of processing 1000 postpaid CDRs -func TestV2CdrsPsqlProcessPostpaidExternalCdrBenchmark(t *testing.T) { +func TestV2CDRsPSQLProcessPostpaidExternalCdrBenchmark(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "benchpostpaidcdr", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "benchpostpaidcdr", OriginHost: "192.168.1.1", Source: utils.UNIT_TEST, RequestType: utils.META_POSTPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", Supplier: "SUPPL1", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", - Usage: "15", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Usage: "15", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string tStart := time.Now() nrCdrs := 1000 for i := 0; i < nrCdrs; i++ { - cdr.AccId = "benchpostpaidcdr" + strconv.Itoa(i) + cdr.OriginID = "benchpostpaidcdr" + strconv.Itoa(i) if err := cdrsPsqlRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -380,7 +383,7 @@ func TestV2CdrsPsqlProcessPostpaidExternalCdrBenchmark(t *testing.T) { } */ -func TestV2CdrsPsqlKillEngine(t *testing.T) { +func TestV2CDRsPSQLKillEngine(t *testing.T) { if !*testLocal { return } diff --git a/cdrc/cdrc.go b/cdrc/cdrc.go index 9d77c941b..a60c073e8 100644 --- a/cdrc/cdrc.go +++ b/cdrc/cdrc.go @@ -44,7 +44,7 @@ const ( // Understands and processes a specific format of cdr (eg: .csv or .fwv) type RecordsProcessor interface { - ProcessNextRecord() ([]*engine.StoredCdr, error) // Process a single record in the CDR file, return a slice of CDRs since based on configuration we can have more templates + ProcessNextRecord() ([]*engine.CDR, error) // Process a single record in the CDR file, return a slice of CDRs since based on configuration we can have more templates ProcessedRecordsNr() int64 } diff --git a/cdrc/cdrc_local_test.go b/cdrc/cdrc_local_test.go index fb3737c32..1fa731eae 100644 --- a/cdrc/cdrc_local_test.go +++ b/cdrc/cdrc_local_test.go @@ -121,10 +121,8 @@ func TestCsvLclEmptyTables(t *testing.T) { return // No point in going further } } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { - t.Fatal(err.Error()) - } + if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", utils.TBL_CDRS)); err != nil { + t.Fatal(err.Error()) } } diff --git a/cdrc/csv.go b/cdrc/csv.go index 66d5971d5..c6daaaee0 100644 --- a/cdrc/csv.go +++ b/cdrc/csv.go @@ -37,7 +37,7 @@ func NewPartialFlatstoreRecord(record []string, timezone string) (*PartialFlatst if len(record) < 7 { return nil, errors.New("MISSING_IE") } - pr := &PartialFlatstoreRecord{Method: record[0], AccId: record[3] + record[1] + record[2], Values: record} + pr := &PartialFlatstoreRecord{Method: record[0], OriginID: record[3] + record[1] + record[2], Values: record} var err error if pr.Timestamp, err = utils.ParseTimeDetectLayout(record[6], timezone); err != nil { return nil, err @@ -48,7 +48,7 @@ func NewPartialFlatstoreRecord(record []string, timezone string) (*PartialFlatst // This is a partial record received from Flatstore, can be INVITE or BYE and it needs to be paired in order to produce duration type PartialFlatstoreRecord struct { Method string // INVITE or BYE - AccId string // Copute here the AccId + OriginID string // Copute here the OriginID Timestamp time.Time // Timestamp of the event, as written by db_flastore module Values []string // Can contain original values or updated via UpdateValues } @@ -100,7 +100,7 @@ type PartialRecordsCache struct { ttl time.Duration cdrOutDir string csvSep rune - partialRecords map[string]map[string]*PartialFlatstoreRecord // [FileName"][AccId]*PartialRecord + partialRecords map[string]map[string]*PartialFlatstoreRecord // [FileName"][OriginID]*PartialRecord guard *engine.GuardianLock } @@ -131,7 +131,7 @@ func (self *PartialRecordsCache) dumpUnpairedRecords(fileName string) error { } // Search in cache and return the partial record with accountind id defined, prefFilename is searched at beginning because of better match probability -func (self *PartialRecordsCache) GetPartialRecord(accId, prefFileName string) (string, *PartialFlatstoreRecord) { +func (self *PartialRecordsCache) GetPartialRecord(OriginID, prefFileName string) (string, *PartialFlatstoreRecord) { var cachedFilename string var cachedPartial *PartialFlatstoreRecord checkCachedFNames := []string{prefFileName} // Higher probability to match as firstFileName @@ -143,7 +143,7 @@ func (self *PartialRecordsCache) GetPartialRecord(accId, prefFileName string) (s for _, fName := range checkCachedFNames { // Need to lock them individually self.guard.Guard(func() (interface{}, error) { var hasPartial bool - if cachedPartial, hasPartial = self.partialRecords[fName][accId]; hasPartial { + if cachedPartial, hasPartial = self.partialRecords[fName][OriginID]; hasPartial { cachedFilename = fName } return nil, nil @@ -158,15 +158,15 @@ func (self *PartialRecordsCache) GetPartialRecord(accId, prefFileName string) (s func (self *PartialRecordsCache) CachePartial(fileName string, pr *PartialFlatstoreRecord) { self.guard.Guard(func() (interface{}, error) { if fileMp, hasFile := self.partialRecords[fileName]; !hasFile { - self.partialRecords[fileName] = map[string]*PartialFlatstoreRecord{pr.AccId: pr} + self.partialRecords[fileName] = map[string]*PartialFlatstoreRecord{pr.OriginID: pr} if self.ttl != 0 { // Schedule expiry/dump of the just created entry in cache go func() { time.Sleep(self.ttl) self.dumpUnpairedRecords(fileName) }() } - } else if _, hasAccId := fileMp[pr.AccId]; !hasAccId { - self.partialRecords[fileName][pr.AccId] = pr + } else if _, hasOriginID := fileMp[pr.OriginID]; !hasOriginID { + self.partialRecords[fileName][pr.OriginID] = pr } return nil, nil }, 0, fileName) @@ -174,7 +174,7 @@ func (self *PartialRecordsCache) CachePartial(fileName string, pr *PartialFlatst func (self *PartialRecordsCache) UncachePartial(fileName string, pr *PartialFlatstoreRecord) { self.guard.Guard(func() (interface{}, error) { - delete(self.partialRecords[fileName], pr.AccId) // Remove the record out of cache + delete(self.partialRecords[fileName], pr.OriginID) // Remove the record out of cache return nil, nil }, 0, fileName) } @@ -203,7 +203,7 @@ func (self *CsvRecordsProcessor) ProcessedRecordsNr() int64 { return self.processedRecordsNr } -func (self *CsvRecordsProcessor) ProcessNextRecord() ([]*engine.StoredCdr, error) { +func (self *CsvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) { record, err := self.csvReader.Read() if err != nil { return nil, err @@ -231,7 +231,7 @@ func (self *CsvRecordsProcessor) processPartialRecord(record []string) ([]string return nil, err } // Retrieve and complete the record from cache - cachedFilename, cachedPartial := self.partialRecordsCache.GetPartialRecord(pr.AccId, self.fileName) + cachedFilename, cachedPartial := self.partialRecordsCache.GetPartialRecord(pr.OriginID, self.fileName) if cachedPartial == nil { // Not cached, do it here and stop processing self.partialRecordsCache.CachePartial(self.fileName, pr) return nil, nil @@ -245,8 +245,8 @@ func (self *CsvRecordsProcessor) processPartialRecord(record []string) ([]string } // Takes the record from a slice and turns it into StoredCdrs, posting them to the cdrServer -func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.StoredCdr, error) { - recordCdrs := make([]*engine.StoredCdr, 0) // More CDRs based on the number of filters and field templates +func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR, error) { + recordCdrs := make([]*engine.CDR, 0) // More CDRs based on the number of filters and field templates for cdrcId, cdrcCfg := range self.cdrcCfgs { // cdrFields coming from more templates will produce individual storCdr records // Make sure filters are matching filterBreak := false @@ -277,8 +277,8 @@ func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.Store } // Takes the record out of csv and turns it into storedCdr which can be processed by CDRS -func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId string) (*engine.StoredCdr, error) { - storedCdr := &engine.StoredCdr{CdrHost: "0.0.0.0", CdrSource: self.cdrcCfgs[cdrcId].CdrSourceId, ExtraFields: make(map[string]string), Cost: -1} +func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId string) (*engine.CDR, error) { + storedCdr := &engine.CDR{OriginHost: "0.0.0.0", Source: self.cdrcCfgs[cdrcId].CdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var err error var lazyHttpFields []*config.CfgCdrField for _, cdrFldCfg := range self.cdrcCfgs[cdrcId].ContentFields { @@ -313,8 +313,8 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId strin return nil, err } } - storedCdr.CgrId = utils.Sha1(storedCdr.AccId, storedCdr.SetupTime.UTC().String()) - if storedCdr.TOR == utils.DATA && self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor != 0 { + storedCdr.CGRID = utils.Sha1(storedCdr.OriginID, storedCdr.SetupTime.UTC().String()) + if storedCdr.ToR == utils.DATA && self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor != 0 { storedCdr.Usage = time.Duration(float64(storedCdr.Usage.Nanoseconds()) * self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor) } for _, httpFieldCfg := range lazyHttpFields { // Lazy process the http fields diff --git a/cdrc/csv_test.go b/cdrc/csv_test.go index 286eb0457..066f564db 100644 --- a/cdrc/csv_test.go +++ b/cdrc/csv_test.go @@ -48,13 +48,13 @@ func TestCsvRecordForkCdr(t *testing.T) { if err != nil { t.Error("Failed to parse CDR in rated cdr", err) } - expectedCdr := &engine.StoredCdr{ - CgrId: utils.Sha1(cdrRow[3], time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC).String()), - TOR: cdrRow[2], - AccId: cdrRow[3], - CdrHost: "0.0.0.0", // Got it over internal interface - CdrSource: "TEST_CDRC", - ReqType: cdrRow[4], + expectedCdr := &engine.CDR{ + CGRID: utils.Sha1(cdrRow[3], time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC).String()), + 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], @@ -88,11 +88,11 @@ func TestCsvDataMultiplyFactor(t *testing.T) { t.Error("Failed to parse CDR in rated cdr", err) } var sTime time.Time - expectedCdr := &engine.StoredCdr{ - CgrId: utils.Sha1("", sTime.String()), - TOR: cdrRow[0], - CdrHost: "0.0.0.0", - CdrSource: "TEST_CDRC", + expectedCdr := &engine.CDR{ + CGRID: utils.Sha1("", sTime.String()), + ToR: cdrRow[0], + OriginHost: "0.0.0.0", + Source: "TEST_CDRC", Usage: time.Duration(1) * time.Second, ExtraFields: map[string]string{}, Cost: -1, @@ -101,11 +101,11 @@ func TestCsvDataMultiplyFactor(t *testing.T) { t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr) } csvProcessor.cdrcCfgs["*default"].DataUsageMultiplyFactor = 1024 - expectedCdr = &engine.StoredCdr{ - CgrId: utils.Sha1("", sTime.String()), - TOR: cdrRow[0], - CdrHost: "0.0.0.0", - CdrSource: "TEST_CDRC", + expectedCdr = &engine.CDR{ + CGRID: utils.Sha1("", sTime.String()), + ToR: cdrRow[0], + OriginHost: "0.0.0.0", + Source: "TEST_CDRC", Usage: time.Duration(1024) * time.Second, ExtraFields: map[string]string{}, Cost: -1, @@ -114,11 +114,11 @@ func TestCsvDataMultiplyFactor(t *testing.T) { t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr) } cdrRow = []string{"*voice", "1"} - expectedCdr = &engine.StoredCdr{ - CgrId: utils.Sha1("", sTime.String()), - TOR: cdrRow[0], - CdrHost: "0.0.0.0", - CdrSource: "TEST_CDRC", + expectedCdr = &engine.CDR{ + CGRID: utils.Sha1("", sTime.String()), + ToR: cdrRow[0], + OriginHost: "0.0.0.0", + Source: "TEST_CDRC", Usage: time.Duration(1) * time.Second, ExtraFields: map[string]string{}, Cost: -1, diff --git a/cdrc/fwv.go b/cdrc/fwv.go index ddb84241f..b1fffe60d 100644 --- a/cdrc/fwv.go +++ b/cdrc/fwv.go @@ -58,11 +58,11 @@ type FwvRecordsProcessor struct { httpClient *http.Client httpSkipTlsCheck bool timezone string - lineLen int64 // Length of the line in the file - offset int64 // Index of the next byte to process - processedRecordsNr int64 // Number of content records in file - trailerOffset int64 // Index where trailer starts, to be used as boundary when reading cdrs - headerCdr *engine.StoredCdr // Cache here the general purpose stored CDR + lineLen int64 // Length of the line in the file + offset int64 // Index of the next byte to process + processedRecordsNr int64 // Number of content records in file + trailerOffset int64 // Index where trailer starts, to be used as boundary when reading cdrs + headerCdr *engine.CDR // Cache here the general purpose stored CDR } // Sets the line length based on first line, sets offset back to initial after reading @@ -83,7 +83,7 @@ func (self *FwvRecordsProcessor) ProcessedRecordsNr() int64 { return self.processedRecordsNr } -func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.StoredCdr, error) { +func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) { defer func() { self.offset += self.lineLen }() // Schedule increasing the offset once we are out from processing the record if self.offset == 0 { // First time, set the necessary offsets if err := self.setLineLen(); err != nil { @@ -106,7 +106,7 @@ func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.StoredCdr, error return nil, nil } } - recordCdrs := make([]*engine.StoredCdr, 0) // More CDRs based on the number of filters and field templates + recordCdrs := make([]*engine.CDR, 0) // More CDRs based on the number of filters and field templates if self.trailerOffset != 0 && self.offset >= self.trailerOffset { if err := self.processTrailer(); err != nil && err != io.EOF { utils.Logger.Err(fmt.Sprintf(" Read trailer error: %s ", err.Error())) @@ -157,24 +157,24 @@ func (self *FwvRecordsProcessor) recordPassesCfgFilter(record, configKey string) } // Converts a record (header or normal) to StoredCdr -func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string) (*engine.StoredCdr, error) { +func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string) (*engine.CDR, error) { var err error var lazyHttpFields []*config.CfgCdrField var cfgFields []*config.CfgCdrField var duMultiplyFactor float64 - var storedCdr *engine.StoredCdr + var storedCdr *engine.CDR if self.headerCdr != nil { // Clone the header CDR so we can use it as base to future processing (inherit fields defined there) storedCdr = self.headerCdr.Clone() } else { - storedCdr = &engine.StoredCdr{CdrHost: "0.0.0.0", ExtraFields: make(map[string]string), Cost: -1} + storedCdr = &engine.CDR{OriginHost: "0.0.0.0", ExtraFields: make(map[string]string), Cost: -1} } if cfgKey == "*header" { cfgFields = self.dfltCfg.HeaderFields - storedCdr.CdrSource = self.dfltCfg.CdrSourceId + storedCdr.Source = self.dfltCfg.CdrSourceId duMultiplyFactor = self.dfltCfg.DataUsageMultiplyFactor } else { cfgFields = self.cdrcCfgs[cfgKey].ContentFields - storedCdr.CdrSource = self.cdrcCfgs[cfgKey].CdrSourceId + storedCdr.Source = self.cdrcCfgs[cfgKey].CdrSourceId duMultiplyFactor = self.cdrcCfgs[cfgKey].DataUsageMultiplyFactor } for _, cdrFldCfg := range cfgFields { @@ -202,10 +202,10 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string) return nil, err } } - if storedCdr.CgrId == "" && storedCdr.AccId != "" && cfgKey != "*header" { - storedCdr.CgrId = utils.Sha1(storedCdr.AccId, storedCdr.SetupTime.UTC().String()) + if storedCdr.CGRID == "" && storedCdr.OriginID != "" && cfgKey != "*header" { + storedCdr.CGRID = utils.Sha1(storedCdr.OriginID, storedCdr.SetupTime.UTC().String()) } - if storedCdr.TOR == utils.DATA && duMultiplyFactor != 0 { + if storedCdr.ToR == utils.DATA && duMultiplyFactor != 0 { storedCdr.Usage = time.Duration(float64(storedCdr.Usage.Nanoseconds()) * duMultiplyFactor) } for _, httpFieldCfg := range lazyHttpFields { // Lazy process the http fields diff --git a/cdre/cdrexporter.go b/cdre/cdrexporter.go index 0e9fddc81..00fbe67d9 100644 --- a/cdre/cdrexporter.go +++ b/cdre/cdrexporter.go @@ -52,7 +52,7 @@ const ( var err error -func NewCdrExporter(cdrs []*engine.StoredCdr, cdrDb engine.CdrStorage, exportTpl *config.CdreConfig, cdrFormat string, fieldSeparator rune, exportId string, +func NewCdrExporter(cdrs []*engine.CDR, cdrDb engine.CdrStorage, exportTpl *config.CdreConfig, cdrFormat string, fieldSeparator rune, exportId string, dataUsageMultiplyFactor, smsUsageMultiplyFactor, genericUsageMultiplyFactor, costMultiplyFactor float64, costShiftDigits, roundDecimals, cgrPrecision int, maskDestId string, maskLen int, httpSkipTlsCheck bool, timezone string) (*CdrExporter, error) { if len(cdrs) == 0 { // Nothing to export @@ -84,7 +84,7 @@ func NewCdrExporter(cdrs []*engine.StoredCdr, cdrDb engine.CdrStorage, exportTpl } type CdrExporter struct { - cdrs []*engine.StoredCdr + cdrs []*engine.CDR cdrDb engine.CdrStorage // Used to extract cost_details if these are requested exportTemplate *config.CdreConfig cdrFormat string // csv, fwv @@ -107,14 +107,14 @@ type CdrExporter struct { totalCost float64 firstExpOrderId, lastExpOrderId int64 - positiveExports []string // CGRIds of successfully exported CDRs - negativeExports map[string]string // CgrIds of failed exports + positiveExports []string // CGRIDs of successfully exported CDRs + negativeExports map[string]string // CGRIDs of failed exports } // Return Json marshaled callCost attached to // Keep it separately so we test only this part in local tests -func (cdre *CdrExporter) getCdrCostDetails(cgrId, runId string) (string, error) { - cc, err := cdre.cdrDb.GetCallCostLog(cgrId, "", runId) +func (cdre *CdrExporter) getCdrCostDetails(CGRID, runId string) (string, error) { + cc, err := cdre.cdrDb.GetCallCostLog(CGRID, runId) if err != nil { return "", err } else if cc == nil { @@ -124,7 +124,7 @@ func (cdre *CdrExporter) getCdrCostDetails(cgrId, runId string) (string, error) return string(ccJson), nil } -func (cdre *CdrExporter) getCombimedCdrFieldVal(processedCdr *engine.StoredCdr, cfgCdrFld *config.CfgCdrField) (string, error) { +func (cdre *CdrExporter) getCombimedCdrFieldVal(processedCdr *engine.CDR, cfgCdrFld *config.CfgCdrField) (string, error) { var combinedVal string // Will result as combination of the field values, filters must match for _, filterRule := range cfgCdrFld.FieldFilter { fltrPass, ftrPassValue := processedCdr.PassesFieldFilter(filterRule) @@ -132,7 +132,7 @@ func (cdre *CdrExporter) getCombimedCdrFieldVal(processedCdr *engine.StoredCdr, return "", nil } for _, cdr := range cdre.cdrs { - if cdr.CgrId != processedCdr.CgrId { + if cdr.CGRID != processedCdr.CGRID { continue // We only care about cdrs with same primary cdr behind } if cdr.FieldAsString(&utils.RSRField{Id: filterRule.Id}) == ftrPassValue { // First CDR with filte @@ -153,7 +153,7 @@ func (cdre *CdrExporter) maskedDestination(destination string) bool { return false } -func (cdre *CdrExporter) getDateTimeFieldVal(cdr *engine.StoredCdr, cfgCdrFld *config.CfgCdrField) (string, error) { +func (cdre *CdrExporter) getDateTimeFieldVal(cdr *engine.CDR, cfgCdrFld *config.CfgCdrField) (string, error) { if len(cfgCdrFld.Value) == 0 { return "", nil } @@ -174,7 +174,7 @@ func (cdre *CdrExporter) getDateTimeFieldVal(cdr *engine.StoredCdr, cfgCdrFld *c } // Extracts the value specified by cfgHdr out of cdr -func (cdre *CdrExporter) cdrFieldValue(cdr *engine.StoredCdr, cfgCdrFld *config.CfgCdrField) (string, error) { +func (cdre *CdrExporter) cdrFieldValue(cdr *engine.CDR, cfgCdrFld *config.CfgCdrField) (string, error) { for _, fltrRl := range cfgCdrFld.FieldFilter { if fltrPass, _ := cdr.PassesFieldFilter(fltrRl); !fltrPass { return "", fmt.Errorf("Field: %s not matching filter rule %v", fltrRl.Id, fltrRl) @@ -189,7 +189,7 @@ func (cdre *CdrExporter) cdrFieldValue(cdr *engine.StoredCdr, cfgCdrFld *config. var cdrVal string switch rsrFld.Id { case COST_DETAILS: // Special case when we need to further extract cost_details out of logDb - if cdr.ExtraFields[COST_DETAILS], err = cdre.getCdrCostDetails(cdr.CgrId, cdr.MediationRunId); err != nil { + if cdr.ExtraFields[COST_DETAILS], err = cdre.getCdrCostDetails(cdr.CGRID, cdr.RunID); err != nil { return "", err } else { cdrVal = cdr.FieldAsString(rsrFld) @@ -229,16 +229,16 @@ func (cdre *CdrExporter) metaHandler(tag, arg string) (string, error) { case META_NRCDRS: return strconv.Itoa(cdre.numberOfRecords), nil case META_DURCDRS: - emulatedCdr := &engine.StoredCdr{TOR: utils.VOICE, Usage: cdre.totalDuration} + emulatedCdr := &engine.CDR{ToR: utils.VOICE, Usage: cdre.totalDuration} return emulatedCdr.FormatUsage(arg), nil case META_SMSUSAGE: - emulatedCdr := &engine.StoredCdr{TOR: utils.SMS, Usage: cdre.totalSmsUsage} + emulatedCdr := &engine.CDR{ToR: utils.SMS, Usage: cdre.totalSmsUsage} return emulatedCdr.FormatUsage(arg), nil case META_GENERICUSAGE: - emulatedCdr := &engine.StoredCdr{TOR: utils.GENERIC, Usage: cdre.totalGenericUsage} + emulatedCdr := &engine.CDR{ToR: utils.GENERIC, Usage: cdre.totalGenericUsage} return emulatedCdr.FormatUsage(arg), nil case META_DATAUSAGE: - emulatedCdr := &engine.StoredCdr{TOR: utils.DATA, Usage: cdre.totalDataUsage} + emulatedCdr := &engine.CDR{ToR: utils.DATA, Usage: cdre.totalDataUsage} return emulatedCdr.FormatUsage(arg), nil case META_COSTCDRS: return strconv.FormatFloat(utils.Round(cdre.totalCost, cdre.roundDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64), nil @@ -311,18 +311,18 @@ func (cdre *CdrExporter) composeTrailer() error { } // Write individual cdr into content buffer, build stats -func (cdre *CdrExporter) processCdr(cdr *engine.StoredCdr) error { - if cdr == nil || len(cdr.CgrId) == 0 { // We do not export empty CDRs +func (cdre *CdrExporter) processCdr(cdr *engine.CDR) error { + if cdr == nil || len(cdr.CGRID) == 0 { // We do not export empty CDRs return nil } else if cdr.ExtraFields == nil { // Avoid assignment in nil map if not initialized cdr.ExtraFields = make(map[string]string) } // Cost multiply - if cdre.dataUsageMultiplyFactor != 0.0 && cdr.TOR == utils.DATA { + if cdre.dataUsageMultiplyFactor != 0.0 && cdr.ToR == utils.DATA { cdr.UsageMultiply(cdre.dataUsageMultiplyFactor, cdre.cgrPrecision) - } else if cdre.smsUsageMultiplyFactor != 0 && cdr.TOR == utils.SMS { + } else if cdre.smsUsageMultiplyFactor != 0 && cdr.ToR == utils.SMS { cdr.UsageMultiply(cdre.smsUsageMultiplyFactor, cdre.cgrPrecision) - } else if cdre.genericUsageMultiplyFactor != 0 && cdr.TOR == utils.GENERIC { + } else if cdre.genericUsageMultiplyFactor != 0 && cdr.ToR == utils.GENERIC { cdr.UsageMultiply(cdre.genericUsageMultiplyFactor, cdre.cgrPrecision) } if cdre.costMultiplyFactor != 0.0 { @@ -363,12 +363,12 @@ func (cdre *CdrExporter) processCdr(cdr *engine.StoredCdr) error { } } if err != nil { - utils.Logger.Err(fmt.Sprintf(" Cannot export CDR with cgrid: %s and runid: %s, error: %s", cdr.CgrId, cdr.MediationRunId, err.Error())) + utils.Logger.Err(fmt.Sprintf(" Cannot export CDR with CGRID: %s and runid: %s, error: %s", cdr.CGRID, cdr.RunID, err.Error())) return err } fmtOut := outVal if fmtOut, err = utils.FmtFieldWidth(outVal, cfgFld.Width, cfgFld.Strip, cfgFld.Padding, cfgFld.Mandatory); err != nil { - utils.Logger.Err(fmt.Sprintf(" Cannot export CDR with cgrid: %s, runid: %s, fieldName: %s, fieldValue: %s, error: %s", cdr.CgrId, cdr.MediationRunId, cfgFld.Tag, outVal, err.Error())) + utils.Logger.Err(fmt.Sprintf(" Cannot export CDR with CGRID: %s, runid: %s, fieldName: %s, fieldValue: %s, error: %s", cdr.CGRID, cdr.RunID, cfgFld.Tag, outVal, err.Error())) return err } cdrRow[idx] += fmtOut @@ -386,27 +386,27 @@ func (cdre *CdrExporter) processCdr(cdr *engine.StoredCdr) error { cdre.lastCdrATime = cdr.AnswerTime } cdre.numberOfRecords += 1 - if cdr.TOR == utils.VOICE { // Only count duration for non data cdrs + if cdr.ToR == utils.VOICE { // Only count duration for non data cdrs cdre.totalDuration += cdr.Usage } - if cdr.TOR == utils.SMS { // Count usage for SMS + if cdr.ToR == utils.SMS { // Count usage for SMS cdre.totalSmsUsage += cdr.Usage } - if cdr.TOR == utils.GENERIC { // Count usage for GENERIC + if cdr.ToR == utils.GENERIC { // Count usage for GENERIC cdre.totalGenericUsage += cdr.Usage } - if cdr.TOR == utils.DATA { // Count usage for DATA + if cdr.ToR == utils.DATA { // Count usage for DATA cdre.totalDataUsage += cdr.Usage } if cdr.Cost != -1 { cdre.totalCost += cdr.Cost cdre.totalCost = utils.Round(cdre.totalCost, cdre.roundDecimals, utils.ROUNDING_MIDDLE) } - if cdre.firstExpOrderId > cdr.OrderId || cdre.firstExpOrderId == 0 { - cdre.firstExpOrderId = cdr.OrderId + if cdre.firstExpOrderId > cdr.OrderID || cdre.firstExpOrderId == 0 { + cdre.firstExpOrderId = cdr.OrderID } - if cdre.lastExpOrderId < cdr.OrderId { - cdre.lastExpOrderId = cdr.OrderId + if cdre.lastExpOrderId < cdr.OrderID { + cdre.lastExpOrderId = cdr.OrderID } return nil } @@ -415,9 +415,9 @@ func (cdre *CdrExporter) processCdr(cdr *engine.StoredCdr) error { func (cdre *CdrExporter) processCdrs() error { for _, cdr := range cdre.cdrs { if err := cdre.processCdr(cdr); err != nil { - cdre.negativeExports[cdr.CgrId] = err.Error() + cdre.negativeExports[cdr.CGRID] = err.Error() } else { - cdre.positiveExports = append(cdre.positiveExports, cdr.CgrId) + cdre.positiveExports = append(cdre.positiveExports, cdr.CGRID) } } // Process header and trailer after processing cdrs since the metatag functions can access stats out of built cdrs @@ -524,12 +524,12 @@ func (cdre *CdrExporter) TotalExportedCdrs() int { return cdre.numberOfRecords } -// Return successfully exported CgrIds +// Return successfully exported CGRIDs func (cdre *CdrExporter) PositiveExports() []string { return cdre.positiveExports } -// Return failed exported CgrIds together with the reason +// Return failed exported CGRIDs together with the reason func (cdre *CdrExporter) NegativeExports() map[string]string { return cdre.negativeExports } diff --git a/cdre/cdrexporter_test.go b/cdre/cdrexporter_test.go index a2f7f2763..0960c8b8f 100644 --- a/cdre/cdrexporter_test.go +++ b/cdre/cdrexporter_test.go @@ -29,34 +29,34 @@ import ( func TestCdreGetCombimedCdrFieldVal(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() - cdrs := []*engine.StoredCdr{ - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + cdrs := []*engine.CDR{ + &engine.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, MediationRunId: "RUN_RTL", Cost: 1.01}, - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Usage: time.Duration(10) * time.Second, RunID: "RUN_RTL", Cost: 1.01}, + &engine.CDR{CGRID: utils.Sha1("dsafdsaf2", 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, MediationRunId: "CUSTOMER1", Cost: 2.01}, - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Usage: time.Duration(10) * time.Second, RunID: "CUSTOMER1", Cost: 2.01}, + &engine.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, MediationRunId: "CUSTOMER1", Cost: 3.01}, - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Usage: time.Duration(10) * time.Second, RunID: "CUSTOMER1", Cost: 3.01}, + &engine.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, MediationRunId: utils.DEFAULT_RUNID, Cost: 4.01}, - &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 4.01}, + &engine.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: "1000", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), - Usage: time.Duration(10) * time.Second, MediationRunId: "RETAIL1", Cost: 5.01}, + Usage: time.Duration(10) * time.Second, RunID: "RETAIL1", Cost: 5.01}, } cdre, err := NewCdrExporter(cdrs, nil, cfg.CdreProfiles["*default"], cfg.CdreProfiles["*default"].CdrFormat, cfg.CdreProfiles["*default"].FieldSeparator, "firstexport", 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error("Unexpected error received: ", err) } - fltrRule, _ := utils.ParseRSRFields("~MediationRunId:s/default/RUN_RTL/", utils.INFIELD_SEP) + fltrRule, _ := utils.ParseRSRFields("~RunID:s/default/RUN_RTL/", utils.INFIELD_SEP) val, _ := utils.ParseRSRFields(utils.COST, utils.INFIELD_SEP) cfgCdrFld := &config.CfgCdrField{Tag: "cost", Type: "cdrfield", FieldId: utils.COST, Value: val, FieldFilter: fltrRule} if costVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil { @@ -64,7 +64,7 @@ func TestCdreGetCombimedCdrFieldVal(t *testing.T) { } else if costVal != "1.01" { t.Error("Expecting: 1.01, received: ", costVal) } - fltrRule, _ = utils.ParseRSRFields("~MediationRunId:s/default/RETAIL1/", utils.INFIELD_SEP) + fltrRule, _ = utils.ParseRSRFields("~RunID:s/default/RETAIL1/", utils.INFIELD_SEP) val, _ = utils.ParseRSRFields(utils.ACCOUNT, utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: utils.ACCOUNT, Type: "cdrfield", FieldId: utils.ACCOUNT, Value: val, FieldFilter: fltrRule} if acntVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil { @@ -76,10 +76,10 @@ func TestCdreGetCombimedCdrFieldVal(t *testing.T) { func TestGetDateTimeFieldVal(t *testing.T) { cdreTst := new(CdrExporter) - cdrTst := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + cdrTst := &engine.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, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01, + Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 1.01, ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}} val, _ := utils.ParseRSRFields("stop_time", utils.INFIELD_SEP) layout := "2006-01-02 15:04:05" @@ -105,10 +105,10 @@ func TestGetDateTimeFieldVal(t *testing.T) { func TestCdreCdrFieldValue(t *testing.T) { cdre := new(CdrExporter) - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.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, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01} + Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 1.01} val, _ := utils.ParseRSRFields(utils.DESTINATION, utils.INFIELD_SEP) cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: "cdrfield", FieldId: utils.DESTINATION, Value: val} if val, err := cdre.cdrFieldValue(cdr, cfgCdrFld); err != nil { diff --git a/cdre/csv_test.go b/cdre/csv_test.go index 647f8379a..0990c7a80 100644 --- a/cdre/csv_test.go +++ b/cdre/csv_test.go @@ -33,13 +33,14 @@ import ( func TestCsvCdrWriter(t *testing.T) { writer := &bytes.Buffer{} cfg, _ := config.NewDefaultCGRConfig() - storedCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + storedCdr1 := &engine.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, MediationRunId: utils.DEFAULT_RUNID, + 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, } - cdre, err := NewCdrExporter([]*engine.StoredCdr{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, ',', "firstexport", 0.0, 0.0, 0.0, 0.0, 0, 4, + cdre, err := NewCdrExporter([]*engine.CDR{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, ',', "firstexport", 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error("Unexpected error received: ", err) @@ -61,13 +62,13 @@ func TestCsvCdrWriter(t *testing.T) { func TestAlternativeFieldSeparator(t *testing.T) { writer := &bytes.Buffer{} cfg, _ := config.NewDefaultCGRConfig() - storedCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + storedCdr1 := &engine.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, MediationRunId: utils.DEFAULT_RUNID, + 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, } - cdre, err := NewCdrExporter([]*engine.StoredCdr{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, '|', + cdre, err := NewCdrExporter([]*engine.CDR{storedCdr1}, nil, cfg.CdreProfiles["*default"], utils.CSV, '|', "firstexport", 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error("Unexpected error received: ", err) diff --git a/cdre/fixedwidth_test.go b/cdre/fixedwidth_test.go index f0e15a71f..ffdd1f747 100644 --- a/cdre/fixedwidth_test.go +++ b/cdre/fixedwidth_test.go @@ -118,16 +118,16 @@ func TestWriteCdr(t *testing.T) { ContentFields: contentCfgFlds, TrailerFields: trailerCfgFlds, } - cdr := &engine.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), - TOR: utils.VOICE, OrderId: 1, AccId: "dsafdsaf", CdrHost: "192.168.1.1", - ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.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", 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, MediationRunId: 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"}, } - cdre, err := NewCdrExporter([]*engine.StoredCdr{cdr}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0.0, 0.0, 0, 4, + cdre, err := NewCdrExporter([]*engine.CDR{cdr}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error(err) @@ -176,33 +176,33 @@ func TestWriteCdrs(t *testing.T) { ContentFields: contentCfgFlds, TrailerFields: trailerCfgFlds, } - cdr1 := &engine.StoredCdr{CgrId: utils.Sha1("aaa1", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), - TOR: utils.VOICE, OrderId: 2, AccId: "aaa1", CdrHost: "192.168.1.1", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + cdr1 := &engine.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", 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), - Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 2.25, + Usage: time.Duration(10) * time.Second, RunID: utils.DEFAULT_RUNID, Cost: 2.25, ExtraFields: map[string]string{"productnumber": "12341", "fieldextr2": "valextr2"}, } - cdr2 := &engine.StoredCdr{CgrId: utils.Sha1("aaa2", time.Date(2013, 11, 7, 7, 42, 20, 0, time.UTC).String()), - TOR: utils.VOICE, OrderId: 4, AccId: "aaa2", CdrHost: "192.168.1.2", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: "cgrates.org", + cdr2 := &engine.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", 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, MediationRunId: 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 := &engine.StoredCdr{} - cdr4 := &engine.StoredCdr{CgrId: utils.Sha1("aaa3", time.Date(2013, 11, 7, 9, 42, 18, 0, time.UTC).String()), - TOR: utils.VOICE, OrderId: 3, AccId: "aaa4", CdrHost: "192.168.1.4", ReqType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr3 := &engine.CDR{} + cdr4 := &engine.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", 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, MediationRunId: 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() - cdre, err := NewCdrExporter([]*engine.StoredCdr{cdr1, cdr2, cdr3, cdr4}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', + cdre, err := NewCdrExporter([]*engine.CDR{cdr1, cdr2, cdr3, cdr4}, nil, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error(err) diff --git a/cmd/cgr-loader/migrator_rc8.go b/cmd/cgr-loader/migrator_rc8.go index 5f5b29671..421da2e40 100644 --- a/cmd/cgr-loader/migrator_rc8.go +++ b/cmd/cgr-loader/migrator_rc8.go @@ -430,7 +430,7 @@ func (mig MigratorRC8) migrateDerivedChargers() error { } } newDcs := &utils.DerivedChargers{ - DestinationIds: make(utils.StringMap), + DestinationIDs: make(utils.StringMap), Chargers: oldDcs, } newDcsMap[key] = newDcs diff --git a/config/cdreconfig.go b/config/cdreconfig.go index fd1e78ee2..55a98c3b5 100644 --- a/config/cdreconfig.go +++ b/config/cdreconfig.go @@ -23,14 +23,14 @@ type CdreConfig struct { CdrFormat string FieldSeparator rune DataUsageMultiplyFactor float64 - SmsUsageMultiplyFactor float64 + SMSUsageMultiplyFactor float64 GenericUsageMultiplyFactor float64 CostMultiplyFactor float64 CostRoundingDecimals int CostShiftDigits int - MaskDestId string + MaskDestinationID string MaskLength int - ExportDir string + ExportFolder string HeaderFields []*CfgCdrField ContentFields []*CfgCdrField TrailerFields []*CfgCdrField @@ -52,7 +52,7 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error { self.DataUsageMultiplyFactor = *jsnCfg.Data_usage_multiply_factor } if jsnCfg.Sms_usage_multiply_factor != nil { - self.SmsUsageMultiplyFactor = *jsnCfg.Sms_usage_multiply_factor + self.SMSUsageMultiplyFactor = *jsnCfg.Sms_usage_multiply_factor } if jsnCfg.Generic_usage_multiply_factor != nil { self.GenericUsageMultiplyFactor = *jsnCfg.Generic_usage_multiply_factor @@ -67,13 +67,13 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error { self.CostShiftDigits = *jsnCfg.Cost_shift_digits } if jsnCfg.Mask_destination_id != nil { - self.MaskDestId = *jsnCfg.Mask_destination_id + self.MaskDestinationID = *jsnCfg.Mask_destination_id } if jsnCfg.Mask_length != nil { self.MaskLength = *jsnCfg.Mask_length } - if jsnCfg.Export_dir != nil { - self.ExportDir = *jsnCfg.Export_dir + if jsnCfg.Export_folder != nil { + self.ExportFolder = *jsnCfg.Export_folder } if jsnCfg.Header_fields != nil { if self.HeaderFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Header_fields); err != nil { @@ -99,14 +99,14 @@ func (self *CdreConfig) Clone() *CdreConfig { clnCdre.CdrFormat = self.CdrFormat clnCdre.FieldSeparator = self.FieldSeparator clnCdre.DataUsageMultiplyFactor = self.DataUsageMultiplyFactor - clnCdre.SmsUsageMultiplyFactor = self.SmsUsageMultiplyFactor + clnCdre.SMSUsageMultiplyFactor = self.SMSUsageMultiplyFactor clnCdre.GenericUsageMultiplyFactor = self.GenericUsageMultiplyFactor clnCdre.CostMultiplyFactor = self.CostMultiplyFactor clnCdre.CostRoundingDecimals = self.CostRoundingDecimals clnCdre.CostShiftDigits = self.CostShiftDigits - clnCdre.MaskDestId = self.MaskDestId + clnCdre.MaskDestinationID = self.MaskDestinationID clnCdre.MaskLength = self.MaskLength - clnCdre.ExportDir = self.ExportDir + clnCdre.ExportFolder = self.ExportFolder clnCdre.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields)) for idx, fld := range self.HeaderFields { clonedVal := *fld diff --git a/config/cdreconfig_test.go b/config/cdreconfig_test.go index 84a95d8f4..66e054d34 100644 --- a/config/cdreconfig_test.go +++ b/config/cdreconfig_test.go @@ -44,9 +44,9 @@ func TestCdreCfgClone(t *testing.T) { CostMultiplyFactor: 1.0, CostRoundingDecimals: -1, CostShiftDigits: 0, - MaskDestId: "MASKED_DESTINATIONS", + MaskDestinationID: "MASKED_DESTINATIONS", MaskLength: 0, - ExportDir: "/var/log/cgrates/cdre", + ExportFolder: "/var/log/cgrates/cdre", ContentFields: initContentFlds, } eClnContentFlds := []*CfgCdrField{ @@ -66,9 +66,9 @@ func TestCdreCfgClone(t *testing.T) { CostMultiplyFactor: 1.0, CostRoundingDecimals: -1, CostShiftDigits: 0, - MaskDestId: "MASKED_DESTINATIONS", + MaskDestinationID: "MASKED_DESTINATIONS", MaskLength: 0, - ExportDir: "/var/log/cgrates/cdre", + ExportFolder: "/var/log/cgrates/cdre", HeaderFields: emptyFields, ContentFields: eClnContentFlds, TrailerFields: emptyFields, diff --git a/config/cfg_data.json b/config/cfg_data.json index a6acc1ee6..77f20a7da 100644 --- a/config/cfg_data.json +++ b/config/cfg_data.json @@ -33,7 +33,7 @@ "run_delay": 1, "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value - {"field_id": "TOR", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, + {"field_id": "ToR", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, {"field_id": "AnswerTime", "value": "1"}, {"field_id": "Usage", "value": "~9:s/^(\\d+)$/${1}s/"}, ], diff --git a/config/cfg_data2.json b/config/cfg_data2.json index 822dd1f09..67b846168 100644 --- a/config/cfg_data2.json +++ b/config/cfg_data2.json @@ -8,7 +8,7 @@ "data_usage_multiply_factor": 0.000976563, "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value - {"field_id": "TOR", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, + {"field_id": "ToR", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, {"field_id": "AnswerTime", "value": "2"}, ], }, diff --git a/config/config_defaults.go b/config/config_defaults.go index fa1a60cb8..b3ac16feb 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -133,20 +133,20 @@ const CGRATES_CFG_JSON = ` "field_separator": ",", "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) - "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) + "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export "mask_length": 0, // length of the destination suffix to be masked - "export_dir": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed + "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed "header_fields": [], // template of the exported header fields "content_fields": [ // template of the exported content fields - {"tag": "CgrId", "field_id": "CgrId", "type": "*composed", "value": "CgrId"}, - {"tag":"RunId", "field_id": "MediationRunId", "type": "*composed", "value": "MediationRunId"}, - {"tag":"Tor", "field_id": "TOR", "type": "*composed", "value": "TOR"}, - {"tag":"AccId", "field_id": "AccId", "type": "*composed", "value": "AccId"}, - {"tag":"ReqType", "field_id": "ReqType", "type": "*composed", "value": "ReqType"}, + {"tag": "CGRID", "field_id": "CGRID", "type": "*composed", "value": "CGRID"}, + {"tag":"RunID", "field_id": "RunID", "type": "*composed", "value": "RunID"}, + {"tag":"TOR", "field_id": "ToR", "type": "*composed", "value": "ToR"}, + {"tag":"OriginID", "field_id": "OriginID", "type": "*composed", "value": "OriginID"}, + {"tag":"RequestType", "field_id": "RequestType", "type": "*composed", "value": "RequestType"}, {"tag":"Direction", "field_id": "Direction", "type": "*composed", "value": "Direction"}, {"tag":"Tenant", "field_id": "Tenant", "type": "*composed", "value": "Tenant"}, {"tag":"Category", "field_id": "Category", "type": "*composed", "value": "Category"}, @@ -183,18 +183,18 @@ const CGRATES_CFG_JSON = ` "partial_record_cache": "10s", // duration to cache partial records when not pairing "header_fields": [], // template of the import header fields "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value - {"tag": "tor", "field_id": "TOR", "type": "*composed", "value": "2", "mandatory": true}, - {"tag": "accid", "field_id": "AccId", "type": "*composed", "value": "3", "mandatory": true}, - {"tag": "reqtype", "field_id": "ReqType", "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}, - {"tag": "subject", "field_id": "Subject", "type": "*composed", "value": "9", "mandatory": true}, - {"tag": "destination", "field_id": "Destination", "type": "*composed", "value": "10", "mandatory": true}, - {"tag": "setup_time", "field_id": "SetupTime", "type": "*composed", "value": "11", "mandatory": true}, - {"tag": "answer_time", "field_id": "AnswerTime", "type": "*composed", "value": "12", "mandatory": true}, - {"tag": "usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true}, + {"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}, + {"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "9", "mandatory": true}, + {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "10", "mandatory": true}, + {"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "11", "mandatory": true}, + {"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "12", "mandatory": true}, + {"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true}, ], "trailer_fields": [], // template of the import trailer fields } @@ -297,10 +297,10 @@ const CGRATES_CFG_JSON = ` "dry_run": false, // do not send the CDRs to CDRS, just parse them "request_filter": "Subscription-Id>Subscription-Id-Type(0)", // filter requests processed by this processor "continue_on_success": false, // continue to the next template if executed - "ccr_fields":[ // fields taken out of CCR and used in internal requests - {"tag": "TOR", "field_id": "TOR", "type": "*composed", "value": "^*voice", "mandatory": true}, - {"tag": "ACCID", "field_id": "AccId", "type": "*composed", "value": "Session-Id", "mandatory": true}, - {"tag": "RequestType", "field_id": "ReqType", "type": "*composed", "value": "^*users", "mandatory": true}, + "ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + {"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true}, + {"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true}, + {"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*users", "mandatory": true}, {"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true}, {"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^*users", "mandatory": true}, {"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true}, @@ -362,7 +362,7 @@ const CGRATES_CFG_JSON = ` "response_group": "03", // determines how taxes are grouped for the response <03|13> "response_type": "D4", // determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response "regulatory_code": "03", // provider type - "client_tracking": "CgrId", // template extracting client information out of StoredCdr; <$RSRFields> + "client_tracking": "CGRID", // template extracting client information out of StoredCdr; <$RSRFields> "customer_number": "Subject", // template extracting customer number out of StoredCdr; <$RSRFields> "orig_number": "Subject", // template extracting origination number out of StoredCdr; <$RSRFields> "term_number": "Destination", // template extracting termination number out of StoredCdr; <$RSRFields> diff --git a/config/config_json_test.go b/config/config_json_test.go index dba9f6f9d..da14de246 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -19,6 +19,7 @@ along with this program. If not, see package config import ( + "encoding/json" "reflect" "strings" "testing" @@ -181,67 +182,67 @@ func TestDfCdrStatsJsonCfg(t *testing.T) { func TestDfCdreJsonCfgs(t *testing.T) { eFields := []*CdrFieldJsonCfg{} eContentFlds := []*CdrFieldJsonCfg{ - &CdrFieldJsonCfg{Tag: utils.StringPointer("CgrId"), + &CdrFieldJsonCfg{Tag: utils.StringPointer("CGRID"), Field_id: utils.StringPointer(utils.CGRID), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.CGRID)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("RunId"), + &CdrFieldJsonCfg{Tag: utils.StringPointer("RunID"), Field_id: utils.StringPointer(utils.MEDI_RUNID), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.MEDI_RUNID)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("Tor"), + &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.TOR), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.TOR)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("AccId"), + &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.ACCID), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ACCID)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("ReqType"), + &CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.REQTYPE), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.REQTYPE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Direction"), Field_id: utils.StringPointer(utils.DIRECTION), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.DIRECTION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"), Field_id: utils.StringPointer(utils.TENANT), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.TENANT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.CATEGORY), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.CATEGORY)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.ACCOUNT), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ACCOUNT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.SUBJECT), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.SUBJECT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.DESTINATION), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.DESTINATION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SETUP_TIME), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.SETUP_TIME), Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.ANSWER_TIME), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.ANSWER_TIME), Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.USAGE), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.USAGE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"), Field_id: utils.StringPointer(utils.COST), - Type: utils.StringPointer("*composed"), + Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer(utils.COST)}, } eCfg := map[string]*CdreJsonCfg{ @@ -256,7 +257,7 @@ func TestDfCdreJsonCfgs(t *testing.T) { Cost_shift_digits: utils.IntPointer(0), Mask_destination_id: utils.StringPointer("MASKED_DESTINATIONS"), Mask_length: utils.IntPointer(0), - Export_dir: utils.StringPointer("/var/log/cgrates/cdre"), + Export_folder: utils.StringPointer("/var/log/cgrates/cdre"), Header_fields: &eFields, Content_fields: &eContentFlds, Trailer_fields: &eFields, @@ -265,36 +266,38 @@ func TestDfCdreJsonCfgs(t *testing.T) { if cfg, err := dfCgrJsonCfg.CdreJsonCfgs(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { - t.Error("Received: ", cfg) + expect, _ := json.Marshal(eCfg) + received, _ := json.Marshal(cfg) + t.Errorf("Expecting: %s, received: %s", string(expect), string(received)) } } func TestDfCdrcJsonCfg(t *testing.T) { eFields := []*CdrFieldJsonCfg{} cdrFields := []*CdrFieldJsonCfg{ - &CdrFieldJsonCfg{Tag: utils.StringPointer("tor"), Field_id: utils.StringPointer(utils.TOR), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.TOR), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("2"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("accid"), Field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("3"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("reqtype"), Field_id: utils.StringPointer(utils.REQTYPE), Type: utils.StringPointer(utils.META_COMPOSED), + &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), + &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), + &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), + &CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.CATEGORY), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("7"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("account"), Field_id: utils.StringPointer(utils.ACCOUNT), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.ACCOUNT), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("8"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("subject"), Field_id: utils.StringPointer(utils.SUBJECT), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.SUBJECT), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("9"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("destination"), Field_id: utils.StringPointer(utils.DESTINATION), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.DESTINATION), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("10"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("setup_time"), Field_id: utils.StringPointer(utils.SETUP_TIME), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SETUP_TIME), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("11"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("answer_time"), Field_id: utils.StringPointer(utils.ANSWER_TIME), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.ANSWER_TIME), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("12"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("usage"), Field_id: utils.StringPointer(utils.USAGE), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.USAGE), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("13"), Mandatory: utils.BoolPointer(true)}, } eCfg := map[string]*CdrcJsonCfg{ @@ -466,7 +469,7 @@ func TestDiameterAgentJsonCfg(t *testing.T) { CCR_fields: &[]*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.TOR), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("^*voice"), Mandatory: utils.BoolPointer(true)}, - &CdrFieldJsonCfg{Tag: utils.StringPointer("ACCID"), Field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.META_COMPOSED), + &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("Session-Id"), Mandatory: utils.BoolPointer(true)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.REQTYPE), Type: utils.StringPointer(utils.META_COMPOSED), Value: utils.StringPointer("^*users"), Mandatory: utils.BoolPointer(true)}, @@ -579,7 +582,7 @@ func TestDfSureTaxJsonCfg(t *testing.T) { Response_group: utils.StringPointer("03"), Response_type: utils.StringPointer("D4"), Regulatory_code: utils.StringPointer("03"), - Client_tracking: utils.StringPointer("CgrId"), + Client_tracking: utils.StringPointer(utils.CGRID), Customer_number: utils.StringPointer("Subject"), Orig_number: utils.StringPointer("Subject"), Term_number: utils.StringPointer("Destination"), diff --git a/config/configcdrc_test.go b/config/configcdrc_test.go index 7acc357cf..621a07b70 100644 --- a/config/configcdrc_test.go +++ b/config/configcdrc_test.go @@ -51,29 +51,29 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { PartialRecordCache: time.Duration(10) * time.Second, HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "tor", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + &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: "accid", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + &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: "reqtype", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + &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), + &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), + &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), + &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), + &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), + &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), + &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: "setup_time", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + &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: "answer_time", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + &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), + &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), @@ -94,29 +94,29 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "tor", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + &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: "accid", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + &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: "reqtype", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + &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), + &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), + &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), + &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), + &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), + &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), + &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: "setup_time", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + &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: "answer_time", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + &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), + &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), @@ -160,29 +160,29 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), HeaderFields: make([]*CfgCdrField, 0), ContentFields: []*CfgCdrField{ - &CfgCdrField{Tag: "tor", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), + &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: "accid", Type: utils.META_COMPOSED, FieldId: utils.ACCID, Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), + &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: "reqtype", Type: utils.META_COMPOSED, FieldId: utils.REQTYPE, Value: utils.ParseRSRFieldsMustCompile("4", utils.INFIELD_SEP), + &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), + &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), + &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), + &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), + &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), + &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), + &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: "setup_time", Type: utils.META_COMPOSED, FieldId: utils.SETUP_TIME, Value: utils.ParseRSRFieldsMustCompile("11", utils.INFIELD_SEP), + &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: "answer_time", Type: utils.META_COMPOSED, FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("12", utils.INFIELD_SEP), + &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), + &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), diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 556d3be69..3804ec076 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -132,7 +132,7 @@ type CdreJsonCfg struct { Cost_shift_digits *int Mask_destination_id *string Mask_length *int - Export_dir *string + Export_folder *string Header_fields *[]*CdrFieldJsonCfg Content_fields *[]*CdrFieldJsonCfg Trailer_fields *[]*CdrFieldJsonCfg diff --git a/data/conf/samples/storage/mongo/cgrates.json b/data/conf/samples/storage/mongo/cgrates.json new file mode 100644 index 000000000..7bd989d5e --- /dev/null +++ b/data/conf/samples/storage/mongo/cgrates.json @@ -0,0 +1,10 @@ +{ +// CGRateS Configuration file used for testing mongo implementation + +"stor_db": { + "db_type": "mongo", // stor database type to use: + "db_port": 27017, // the port to reach the stordb +}, + + +} diff --git a/data/conf/samples/storage/mysql/cgrates.json b/data/conf/samples/storage/mysql/cgrates.json new file mode 100644 index 000000000..fd8b92330 --- /dev/null +++ b/data/conf/samples/storage/mysql/cgrates.json @@ -0,0 +1,13 @@ +{ +// CGRateS Configuration file used for testing mysql implementation + +"stor_db": { // database used to store offline tariff plans and CDRs + "db_type": "mysql", // stor database type to use: + "db_host": "127.0.0.1", // the host to connect to + "db_port": 3306, // the port to reach the stordb + "db_name": "cgrates", // stor database name + "db_user": "cgrates", // username to use when connecting to stordb + "db_passwd": "CGRateS.org", // password to use when connecting to stordb +}, + +} diff --git a/data/conf/samples/storage/postgres/cgrates.json b/data/conf/samples/storage/postgres/cgrates.json new file mode 100644 index 000000000..d1d700a9d --- /dev/null +++ b/data/conf/samples/storage/postgres/cgrates.json @@ -0,0 +1,13 @@ +{ +// CGRateS Configuration file used for testing mysql implementation + +"stor_db": { // database used to store offline tariff plans and CDRs + "db_type": "postgres", // stor database type to use: + "db_host": "127.0.0.1", // the host to connect to + "db_port": 5432, // the port to reach the stordb + "db_name": "cgrates", // stor database name + "db_user": "cgrates", // username to use when connecting to stordb + "db_passwd": "CGRateS.org", // password to use when connecting to stordb +}, + +} diff --git a/data/storage/mongo/create_user.js b/data/storage/mongo/create_user.js new file mode 100644 index 000000000..bcdf06d43 --- /dev/null +++ b/data/storage/mongo/create_user.js @@ -0,0 +1,9 @@ + +db = db.getSiblingDB('admin') +db.createUser( + { + user: "cgrates", + pwd: "CGRateS.org", + roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] + } +) diff --git a/data/storage/mongo/setup_cgr_db.sh b/data/storage/mongo/setup_cgr_db.sh new file mode 100755 index 000000000..4cbc93516 --- /dev/null +++ b/data/storage/mongo/setup_cgr_db.sh @@ -0,0 +1,14 @@ +#! /usr/bin/env sh + + +mongo --quiet create_user.js +cu=$? + +if [ $cu = 0 ]; then + echo "" + echo "\t+++ CGR-DB successfully set-up! +++" + echo "" + exit 0 +fi + + diff --git a/data/storage/mysql/create_cdrs_tables.sql b/data/storage/mysql/create_cdrs_tables.sql index ac7dc3088..3f5e0269d 100644 --- a/data/storage/mysql/create_cdrs_tables.sql +++ b/data/storage/mysql/create_cdrs_tables.sql @@ -1,90 +1,17 @@ - -- --- Table structure for table `cdrs_primary` +-- Table structure for table `cdrs` -- -DROP TABLE IF EXISTS cdrs_primary; -CREATE TABLE cdrs_primary ( +DROP TABLE IF EXISTS cdrs; +CREATE TABLE cdrs ( id int(11) NOT NULL AUTO_INCREMENT, cgrid char(40) NOT NULL, - tor varchar(16) NOT NULL, - accid varchar(64) NOT NULL, - cdrhost varchar(64) NOT NULL, - cdrsource varchar(64) NOT NULL, - reqtype 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, - created_at TIMESTAMP, - deleted_at TIMESTAMP, - PRIMARY KEY (id), - UNIQUE KEY cgrid (cgrid), - KEY answer_time_idx (answer_time), - KEY deleted_at_idx (deleted_at) - -); - --- --- Table structure for table `cdrs_extra` --- - -DROP TABLE IF EXISTS cdrs_extra; -CREATE TABLE cdrs_extra ( - id int(11) NOT NULL AUTO_INCREMENT, - cgrid char(40) NOT NULL, - extra_fields text NOT NULL, - created_at TIMESTAMP, - deleted_at TIMESTAMP, - PRIMARY KEY (id), - UNIQUE KEY cgrid (cgrid), - KEY deleted_at_idx (deleted_at) -); - --- --- Table structure for table `cost_details` --- - -DROP TABLE IF EXISTS cost_details; -CREATE TABLE cost_details ( - id int(11) NOT NULL AUTO_INCREMENT, - cgrid char(40) NOT NULL, - runid varchar(64) NOT NULL, + run_id varchar(64) NOT NULL, + origin_host varchar(64) NOT NULL, + source varchar(64) NOT NULL, + origin_id varchar(64) NOT NULL, tor varchar(16) NOT NULL, - direction varchar(8) NOT NULL, - tenant varchar(128) NOT NULL, - category varchar(32) NOT NULL, - account varchar(128) NOT NULL, - subject varchar(128) NOT NULL, - destination varchar(128) NOT NULL, - cost DECIMAL(20,4) NOT NULL, - timespans text, - cost_source varchar(64) NOT NULL, - created_at TIMESTAMP, - updated_at TIMESTAMP, - deleted_at TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `costid` (`cgrid`,`runid`), - KEY deleted_at_idx (deleted_at) -); - --- --- Table structure for table `rated_cdrs` --- -DROP TABLE IF EXISTS rated_cdrs; -CREATE TABLE `rated_cdrs` ( - id int(11) NOT NULL AUTO_INCREMENT, - cgrid char(40) NOT NULL, - runid varchar(64) NOT NULL, - reqtype varchar(24) NOT NULL, + request_type varchar(24) NOT NULL, direction varchar(8) NOT NULL, tenant varchar(64) NOT NULL, category varchar(32) NOT NULL, @@ -97,12 +24,28 @@ CREATE TABLE `rated_cdrs` ( `usage` DECIMAL(30,9) NOT NULL, supplier varchar(128) NOT NULL, disconnect_cause varchar(64) NOT NULL, - cost DECIMAL(20,4) DEFAULT NULL, + extra_fields text NOT NULL, + cost_source varchar(64) NOT NULL, + cost DECIMAL(20,4) NOT NULL, + cost_details text, extra_info text, created_at TIMESTAMP, updated_at TIMESTAMP, deleted_at TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY cdrrun (cgrid, run_id) +); + +DROP TABLE IF EXISTS sm_costs; +CREATE TABLE sm_costs ( + id int(11) NOT NULL AUTO_INCREMENT, + cgrid char(40) NOT NULL, + run_id varchar(64) NOT NULL, + cost_source varchar(64) NOT NULL, + cost_details text, + created_at TIMESTAMP, + deleted_at TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE KEY `costid` (`cgrid`,`runid`), + UNIQUE KEY costid (cgrid,run_id), KEY deleted_at_idx (deleted_at) -); \ No newline at end of file +); diff --git a/data/storage/postgres/create_cdrs_tables.sql b/data/storage/postgres/create_cdrs_tables.sql index 4aa36828f..3d386ec7e 100644 --- a/data/storage/postgres/create_cdrs_tables.sql +++ b/data/storage/postgres/create_cdrs_tables.sql @@ -1,103 +1,54 @@ - -- --- Table structure for table `cdrs_primary` +-- Table structure for table `cdrs` -- -DROP TABLE IF EXISTS cdrs_primary; -CREATE TABLE cdrs_primary ( - id SERIAL PRIMARY KEY, - cgrid CHAR(40) NOT NULL, - tor VARCHAR(16) NOT NULL, - accid VARCHAR(64) NOT NULL, - cdrhost VARCHAR(64) NOT NULL, - cdrsource VARCHAR(64) NOT NULL, - reqtype 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 NOT NULL, - pdd NUMERIC(12,9) NOT NULL, - answer_time TIMESTAMP NOT NULL, - usage NUMERIC(30,9) NOT NULL, - supplier VARCHAR(128) NOT NULL, - disconnect_cause VARCHAR(64) NOT NULL, - created_at TIMESTAMP, - deleted_at TIMESTAMP, - UNIQUE (cgrid) +DROP TABLE IF EXISTS cdrs; +CREATE TABLE cdrs ( + id SERIAL PRIMARY KEY, + cgrid CHAR(40) NOT NULL, + run_id VARCHAR(64) NOT NULL, + origin_host VARCHAR(64) NOT NULL, + source VARCHAR(64) NOT NULL, + 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 NOT NULL, + pdd NUMERIC(12,9) NOT NULL, + answer_time TIMESTAMP NOT NULL, + usage NUMERIC(30,9) NOT NULL, + supplier VARCHAR(128) NOT NULL, + disconnect_cause VARCHAR(64) NOT NULL, + extra_fields jsonb, + cost_source VARCHAR(64) NOT NULL, + cost NUMERIC(20,4) DEFAULT NULL, + cost_details jsonb, + extra_info text, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP, + UNIQUE (cgrid, run_id) ); -CREATE INDEX answer_time_idx ON cdrs_primary (answer_time); +; +DROP INDEX IF EXISTS deleted_at_cp_idx; CREATE INDEX deleted_at_cp_idx ON cdrs_primary (deleted_at); --- --- Table structure for table `cdrs_extra` --- -DROP TABLE IF EXISTS cdrs_extra; -CREATE TABLE cdrs_extra ( +DROP TABLE IF EXISTS sm_costs; +CREATE TABLE sm_costs ( id SERIAL PRIMARY KEY, cgrid CHAR(40) NOT NULL, - extra_fields jsonb NOT NULL, - created_at TIMESTAMP, - deleted_at TIMESTAMP, - UNIQUE (cgrid) -); -CREATE INDEX deleted_at_ce_idx ON cdrs_extra (deleted_at); - --- --- Table structure for table `cost_details` --- - -DROP TABLE IF EXISTS cost_details; -CREATE TABLE cost_details ( - id SERIAL PRIMARY KEY, - cgrid CHAR(40) NOT NULL, - runid VARCHAR(64) NOT NULL, - tor VARCHAR(16) NOT NULL, - direction VARCHAR(8) NOT NULL, - tenant VARCHAR(128) NOT NULL, - category VARCHAR(32) NOT NULL, - account VARCHAR(128) NOT NULL, - subject VARCHAR(128) NOT NULL, - destination VARCHAR(128) NOT NULL, - cost NUMERIC(20,4) NOT NULL, - timespans jsonb, + run_id VARCHAR(64) NOT NULL, cost_source VARCHAR(64) NOT NULL, + cost_details jsonb, created_at TIMESTAMP, - updated_at TIMESTAMP, deleted_at TIMESTAMP, - UNIQUE (cgrid, runid) + UNIQUE (cgrid, run_id) ); -CREATE INDEX deleted_at_cd_idx ON cost_details (deleted_at); - --- --- Table structure for table `rated_cdrs` --- -DROP TABLE IF EXISTS rated_cdrs; -CREATE TABLE rated_cdrs ( - id SERIAL PRIMARY KEY, - cgrid CHAR(40) NOT NULL, - runid VARCHAR(64) NOT NULL, - reqtype 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 NOT NULL, - pdd NUMERIC(12,9) NOT NULL, - answer_time TIMESTAMP NOT NULL, - usage NUMERIC(30,9) NOT NULL, - supplier VARCHAR(128) NOT NULL, - disconnect_cause VARCHAR(64) NOT NULL, - cost NUMERIC(20,4) DEFAULT NULL, - extra_info text, - created_at TIMESTAMP, - updated_at TIMESTAMP, - deleted_at TIMESTAMP, - UNIQUE (cgrid, runid) -); -CREATE INDEX deleted_at_rc_idx ON rated_cdrs (deleted_at); +DROP INDEX IF EXISTS deleted_at_smcost_idx; +CREATE INDEX deleted_at_smcost_idx ON sm_costs (deleted_at); diff --git a/data/tariffplans/tutorial/Users.csv b/data/tariffplans/tutorial/Users.csv index 699dec1e2..63b36ff9f 100644 --- a/data/tariffplans/tutorial/Users.csv +++ b/data/tariffplans/tutorial/Users.csv @@ -6,7 +6,7 @@ cgrates.org,1001,,Account,1001,10 cgrates.org,1001,,Subject,1001,10 cgrates.org,1001,,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e,10 cgrates.org,1001,,SubscriberId,1001,10 -cgrates.org,1001,,ReqType,*prepaid,10 +cgrates.org,1001,,RequestType,*prepaid,10 cgrates.org,1002,,SysUserName,rif,10 cgrates.org,1002,,RifAttr,RifVal,10 cgrates.org,1002,,Account,1002,10 @@ -18,5 +18,5 @@ cgrates.org,1004,,SysPassword,hisPass321,10 cgrates.org,1004,,Cli,+4986517174964,10 cgrates.org,1004,,Account,1004,10 cgrates.org,1004,,Subject,1004,10 -cgrates.org,1004,,ReqType,*rated,10 +cgrates.org,1004,,RequestType,*rated,10 cgrates.org,1004,,SubscriberId,1004,10 diff --git a/engine/account.go b/engine/account.go index 92d10f48e..747722756 100644 --- a/engine/account.go +++ b/engine/account.go @@ -499,7 +499,6 @@ func (ub *Account) executeActionTriggers(a *Action) { } switch at.ThresholdType { case utils.TRIGGER_MAX_BALANCE: - if b.MatchActionTrigger(at) && b.GetValue() >= at.ThresholdValue { at.Execute(ub, nil) } diff --git a/engine/account_test.go b/engine/account_test.go index 8209a5b36..3f59e332d 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -867,9 +867,9 @@ func TestAccountAddMinuteNil(t *testing.T) { } func TestAccountAddMinutBucketEmpty(t *testing.T) { - mb1 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}} - mb2 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}} - mb3 := &Balance{Value: -10, DestinationIds: utils.StringMap{"OTHER": true}, Directions: utils.StringMap{utils.OUT: true}} + mb1 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)} + mb2 := &Balance{Value: -10, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.NewStringMap(utils.OUT)} + mb3 := &Balance{Value: -10, DestinationIds: utils.StringMap{"OTHER": true}, Directions: utils.NewStringMap(utils.OUT)} ub := &Account{} a := &Action{BalanceType: utils.VOICE, Balance: mb1} ub.debitBalanceAction(a, false) diff --git a/engine/action.go b/engine/action.go index f3d605ec8..e7e265cb9 100644 --- a/engine/action.go +++ b/engine/action.go @@ -197,15 +197,15 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { defaultTemplate := map[string]utils.RSRFields{ - "TOR": utils.ParseRSRFieldsMustCompile("balance_type", utils.INFIELD_SEP), - "CdrHost": utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), - "Direction": utils.ParseRSRFieldsMustCompile("direction", utils.INFIELD_SEP), - "ReqType": utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), - "Tenant": utils.ParseRSRFieldsMustCompile("tenant", utils.INFIELD_SEP), - "Account": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), - "Subject": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), - "Cost": utils.ParseRSRFieldsMustCompile("balance_value", utils.INFIELD_SEP), - "MediationRunId": utils.ParseRSRFieldsMustCompile("^"+utils.META_DEFAULT, utils.INFIELD_SEP), + utils.TOR: utils.ParseRSRFieldsMustCompile("balance_type", utils.INFIELD_SEP), + utils.CDRHOST: utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), + utils.DIRECTION: utils.ParseRSRFieldsMustCompile("direction", utils.INFIELD_SEP), + utils.REQTYPE: utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), + utils.TENANT: utils.ParseRSRFieldsMustCompile("tenant", utils.INFIELD_SEP), + utils.ACCOUNT: utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), + utils.SUBJECT: utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), + utils.COST: utils.ParseRSRFieldsMustCompile("balance_value", utils.INFIELD_SEP), + utils.MEDI_RUNID: utils.ParseRSRFieldsMustCompile("^"+utils.META_DEFAULT, utils.INFIELD_SEP), } template := make(map[string]string) @@ -223,13 +223,13 @@ func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) } // set stored cdr values - var cdrs []*StoredCdr + var cdrs []*CDR for _, action := range acs { if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET}, action.ActionType) || action.Balance == nil { continue // Only log specific actions } - cdr := &StoredCdr{CdrSource: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), AccId: utils.GenUUID(), ExtraFields: make(map[string]string)} - cdr.CgrId = utils.Sha1(cdr.AccId, cdr.SetupTime.String()) + cdr := &CDR{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() for key, rsrFlds := range defaultTemplate { @@ -255,10 +255,7 @@ func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) if cdrStorage == nil { // Only save if the cdrStorage is defined continue } - if err := cdrStorage.SetCdr(cdr); err != nil { - return err - } - if err := cdrStorage.SetRatedCdr(cdr); err != nil { + if err := cdrStorage.SetCDR(cdr, true); err != nil { return err } // FixMe diff --git a/engine/actions_local_test.go b/engine/actions_local_test.go index eea4919f8..c5d30e126 100644 --- a/engine/actions_local_test.go +++ b/engine/actions_local_test.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "flag" "net/rpc" "net/rpc/jsonrpc" "path" @@ -33,6 +34,8 @@ var actsLclCfg *config.CGRConfig var actsLclRpc *rpc.Client var actsLclCfgPath = path.Join(*dataDir, "conf", "samples", "actions") +var waitRater = flag.Int("wait_rater", 100, "Number of miliseconds to wait for rater to start and cache") + func TestActionsLocalInitCfg(t *testing.T) { if !*testLocal { return @@ -61,7 +64,7 @@ func TestActionsLocalStartEngine(t *testing.T) { if !*testLocal { return } - if _, err := StartEngine(actsLclCfgPath, waitRater); err != nil { + if _, err := StartEngine(actsLclCfgPath, *waitRater); err != nil { t.Fatal(err) } } @@ -105,20 +108,20 @@ func TestActionsLocalSetCdrlogActions(t *testing.T) { } else if reply != utils.OK { t.Errorf("Calling ApierV1.ExecuteAction received: %s", reply) } - var rcvedCdrs []*ExternalCdr - if err := actsLclRpc.Call("ApierV2.GetCdrs", utils.RpcCdrsFilter{CdrSources: []string{CDRLOG}}, &rcvedCdrs); err != nil { + var rcvedCdrs []*ExternalCDR + if err := actsLclRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{Sources: []string{CDRLOG}}, &rcvedCdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(rcvedCdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(rcvedCdrs)) - } else if rcvedCdrs[0].TOR != utils.MONETARY || - rcvedCdrs[0].CdrHost != "127.0.0.1" || - rcvedCdrs[0].CdrSource != CDRLOG || - rcvedCdrs[0].ReqType != utils.META_PREPAID || + } else if rcvedCdrs[0].ToR != utils.MONETARY || + rcvedCdrs[0].OriginHost != "127.0.0.1" || + rcvedCdrs[0].Source != CDRLOG || + rcvedCdrs[0].RequestType != utils.META_PREPAID || rcvedCdrs[0].Tenant != "cgrates.org" || rcvedCdrs[0].Account != "dan2904" || rcvedCdrs[0].Subject != "dan2904" || rcvedCdrs[0].Usage != "1" || - rcvedCdrs[0].MediationRunId != utils.META_DEFAULT || + rcvedCdrs[0].RunID != utils.META_DEFAULT || rcvedCdrs[0].Cost != attrsAA.Actions[0].Units { t.Errorf("Received: %+v", rcvedCdrs[0]) } @@ -129,7 +132,7 @@ func TestActionsLocalStopCgrEngine(t *testing.T) { if !*testLocal { return } - if err := KillEngine(waitRater); err != nil { + if err := KillEngine(*waitRater); err != nil { t.Error(err) } } diff --git a/engine/actions_test.go b/engine/actions_test.go index 75b6ef9b9..2b3f7614c 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -1174,9 +1174,9 @@ func TestActionCdrlogEmpty(t *testing.T) { if err != nil { t.Error("Error performing cdrlog action: ", err) } - cdrs := make([]*StoredCdr, 0) + cdrs := make([]*CDR, 0) json.Unmarshal([]byte(cdrlog.ExpirationString), &cdrs) - if len(cdrs) != 1 || cdrs[0].CdrSource != CDRLOG { + if len(cdrs) != 1 || cdrs[0].Source != CDRLOG { t.Errorf("Wrong cdrlogs: %+v", cdrs[0]) } } @@ -1200,7 +1200,7 @@ func TestActionCdrlogWithParams(t *testing.T) { if err != nil { t.Error("Error performing cdrlog action: ", err) } - cdrs := make([]*StoredCdr, 0) + cdrs := make([]*CDR, 0) json.Unmarshal([]byte(cdrlog.ExpirationString), &cdrs) if len(cdrs) != 2 || cdrs[0].Subject != "rif" { @@ -1212,7 +1212,7 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { acnt := &Account{Id: "cgrates.org:dan2904"} cdrlog := &Action{ ActionType: CDRLOG, - ExtraParameters: `{"Subject":"^rif","Destination":"^1234","TOR":"~action_tag:s/^at(.)$/0$1/","AccountId":"~account_id:s/^\\*(.*)$/$1/"}`, + ExtraParameters: `{"Subject":"^rif","Destination":"^1234","ToR":"~action_tag:s/^at(.)$/0$1/","AccountId":"~account_id:s/^\\*(.*)$/$1/"}`, } err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ @@ -1227,7 +1227,7 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) { if err != nil { t.Error("Error performing cdrlog action: ", err) } - cdrs := make([]*StoredCdr, 0) + cdrs := make([]*CDR, 0) json.Unmarshal([]byte(cdrlog.ExpirationString), &cdrs) expectedExtraFields := map[string]string{ "AccountId": "cgrates.org:dan2904", diff --git a/engine/storedcdr.go b/engine/cdr.go similarity index 50% rename from engine/storedcdr.go rename to engine/cdr.go index fba8ac848..599de20de 100644 --- a/engine/storedcdr.go +++ b/engine/cdr.go @@ -31,56 +31,55 @@ import ( "github.com/cgrates/cgrates/utils" ) -func NewStoredCdrFromExternalCdr(extCdr *ExternalCdr, timezone string) (*StoredCdr, error) { +func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) { var err error - storedCdr := &StoredCdr{CgrId: extCdr.CgrId, OrderId: extCdr.OrderId, TOR: extCdr.TOR, AccId: extCdr.AccId, CdrHost: extCdr.CdrHost, CdrSource: extCdr.CdrSource, - ReqType: extCdr.ReqType, Direction: extCdr.Direction, Tenant: extCdr.Tenant, Category: extCdr.Category, Account: extCdr.Account, Subject: extCdr.Subject, - Destination: extCdr.Destination, Supplier: extCdr.Supplier, DisconnectCause: extCdr.DisconnectCause, - MediationRunId: extCdr.MediationRunId, RatedAccount: extCdr.RatedAccount, RatedSubject: extCdr.RatedSubject, Cost: extCdr.Cost, Rated: extCdr.Rated} - if storedCdr.SetupTime, err = utils.ParseTimeDetectLayout(extCdr.SetupTime, timezone); err != nil { + 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} + if cdr.SetupTime, err = utils.ParseTimeDetectLayout(extCdr.SetupTime, timezone); err != nil { return nil, err } - if len(storedCdr.CgrId) == 0 { // Populate CgrId if not present - storedCdr.CgrId = utils.Sha1(storedCdr.AccId, storedCdr.SetupTime.UTC().String()) + if len(cdr.CGRID) == 0 { // Populate CGRID if not present + cdr.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.UTC().String()) } - if storedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(extCdr.AnswerTime, timezone); err != nil { + if cdr.AnswerTime, err = utils.ParseTimeDetectLayout(extCdr.AnswerTime, timezone); err != nil { return nil, err } - if storedCdr.Usage, err = utils.ParseDurationWithSecs(extCdr.Usage); err != nil { + if cdr.Usage, err = utils.ParseDurationWithSecs(extCdr.Usage); err != nil { return nil, err } - if storedCdr.Pdd, err = utils.ParseDurationWithSecs(extCdr.Pdd); err != nil { + 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), storedCdr.CostDetails); err != nil { + if err = json.Unmarshal([]byte(extCdr.CostDetails), cdr.CostDetails); err != nil { return nil, err } } if extCdr.ExtraFields != nil { - storedCdr.ExtraFields = make(map[string]string) + cdr.ExtraFields = make(map[string]string) } for k, v := range extCdr.ExtraFields { - storedCdr.ExtraFields[k] = v + cdr.ExtraFields[k] = v } - return storedCdr, nil + return cdr, nil } -// ToDo: split config to only add here general section -func NewStoredCdrWithDefaults(cfg *config.CGRConfig) *StoredCdr { - return &StoredCdr{TOR: utils.VOICE, ReqType: cfg.DefaultReqType, Direction: utils.OUT, Tenant: cfg.DefaultTenant, Category: cfg.DefaultCategory, +func NewCDRWithDefaults(cfg *config.CGRConfig) *CDR { + return &CDR{ToR: utils.VOICE, RequestType: cfg.DefaultReqType, Direction: utils.OUT, Tenant: cfg.DefaultTenant, Category: cfg.DefaultCategory, ExtraFields: make(map[string]string), Cost: -1} } -// Kinda standard of internal CDR, complies to CDR interface also -type StoredCdr struct { - CgrId string - OrderId int64 // Stor order id used as export order id - TOR string // type of record, meta-field, should map to one of the TORs hardcoded inside the server <*voice|*data|*sms|*generic> - AccId 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 . +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. @@ -88,42 +87,37 @@ type StoredCdr struct { 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 + 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 - MediationRunId string - RatedAccount string // Populated out of rating data - RatedSubject string + CostSource string // The source of this cost Cost float64 - ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation CostDetails *CallCost // Attach the cost details to CDR when possible - Rated bool // Mark the CDR as rated so we do not process it during mediation + 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 } -func (storedCdr *StoredCdr) CostDetailsJson() string { - if storedCdr.CostDetails == nil { - return "" - } - mrshled, _ := json.Marshal(storedCdr.CostDetails) +func (cdr *CDR) CostDetailsJson() string { + mrshled, _ := json.Marshal(cdr.CostDetails) return string(mrshled) } // Used to multiply usage on export -func (storedCdr *StoredCdr) UsageMultiply(multiplyFactor float64, roundDecimals int) { - storedCdr.Usage = time.Duration(int(utils.Round(float64(storedCdr.Usage.Nanoseconds())*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE))) // Rounding down could introduce a slight loss here but only at nanoseconds level +func (cdr *CDR) UsageMultiply(multiplyFactor float64, roundDecimals int) { + cdr.Usage = time.Duration(int(utils.Round(float64(cdr.Usage.Nanoseconds())*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE))) // Rounding down could introduce a slight loss here but only at nanoseconds level } // Used to multiply cost on export -func (storedCdr *StoredCdr) CostMultiply(multiplyFactor float64, roundDecimals int) { - storedCdr.Cost = utils.Round(storedCdr.Cost*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE) +func (cdr *CDR) CostMultiply(multiplyFactor float64, roundDecimals int) { + cdr.Cost = utils.Round(cdr.Cost*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE) } // Format cost as string on export -func (storedCdr *StoredCdr) FormatCost(shiftDecimals, roundDecimals int) string { - cost := storedCdr.Cost +func (cdr *CDR) FormatCost(shiftDecimals, roundDecimals int) string { + cost := cdr.Cost if shiftDecimals != 0 { cost = cost * math.Pow10(shiftDecimals) } @@ -131,216 +125,204 @@ func (storedCdr *StoredCdr) FormatCost(shiftDecimals, roundDecimals int) string } // Formats usage on export -func (storedCdr *StoredCdr) FormatUsage(layout string) string { - if utils.IsSliceMember([]string{utils.DATA, utils.SMS, utils.GENERIC}, storedCdr.TOR) { - return strconv.FormatFloat(utils.Round(storedCdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64) +func (cdr *CDR) FormatUsage(layout string) string { + if utils.IsSliceMember([]string{utils.DATA, utils.SMS, utils.GENERIC}, cdr.ToR) { + return strconv.FormatFloat(utils.Round(cdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64) } switch layout { default: - return strconv.FormatFloat(float64(storedCdr.Usage.Nanoseconds())/1000000000, 'f', -1, 64) + return strconv.FormatFloat(float64(cdr.Usage.Nanoseconds())/1000000000, 'f', -1, 64) } } // Used to retrieve fields as string, primary fields are const labeled -func (storedCdr *StoredCdr) FieldAsString(rsrFld *utils.RSRField) string { +func (cdr *CDR) FieldAsString(rsrFld *utils.RSRField) string { if rsrFld.IsStatic() { // Static values do not care about headers return rsrFld.ParseValue("") } switch rsrFld.Id { case utils.CGRID: - return rsrFld.ParseValue(storedCdr.CgrId) + return rsrFld.ParseValue(cdr.CGRID) case utils.ORDERID: - return rsrFld.ParseValue(strconv.FormatInt(storedCdr.OrderId, 10)) + return rsrFld.ParseValue(strconv.FormatInt(cdr.OrderID, 10)) case utils.TOR: - return rsrFld.ParseValue(storedCdr.TOR) + return rsrFld.ParseValue(cdr.ToR) case utils.ACCID: - return rsrFld.ParseValue(storedCdr.AccId) + return rsrFld.ParseValue(cdr.OriginID) case utils.CDRHOST: - return rsrFld.ParseValue(storedCdr.CdrHost) + return rsrFld.ParseValue(cdr.OriginHost) case utils.CDRSOURCE: - return rsrFld.ParseValue(storedCdr.CdrSource) + return rsrFld.ParseValue(cdr.Source) case utils.REQTYPE: - return rsrFld.ParseValue(storedCdr.ReqType) + return rsrFld.ParseValue(cdr.RequestType) case utils.DIRECTION: - return rsrFld.ParseValue(storedCdr.Direction) + return rsrFld.ParseValue(cdr.Direction) case utils.TENANT: - return rsrFld.ParseValue(storedCdr.Tenant) + return rsrFld.ParseValue(cdr.Tenant) case utils.CATEGORY: - return rsrFld.ParseValue(storedCdr.Category) + return rsrFld.ParseValue(cdr.Category) case utils.ACCOUNT: - return rsrFld.ParseValue(storedCdr.Account) + return rsrFld.ParseValue(cdr.Account) case utils.SUBJECT: - return rsrFld.ParseValue(storedCdr.Subject) + return rsrFld.ParseValue(cdr.Subject) case utils.DESTINATION: - return rsrFld.ParseValue(storedCdr.Destination) + return rsrFld.ParseValue(cdr.Destination) case utils.SETUP_TIME: - return rsrFld.ParseValue(storedCdr.SetupTime.Format(time.RFC3339)) + return rsrFld.ParseValue(cdr.SetupTime.Format(time.RFC3339)) case utils.PDD: - return strconv.FormatFloat(storedCdr.Pdd.Seconds(), 'f', -1, 64) + return strconv.FormatFloat(cdr.PDD.Seconds(), 'f', -1, 64) case utils.ANSWER_TIME: - return rsrFld.ParseValue(storedCdr.AnswerTime.Format(time.RFC3339)) + return rsrFld.ParseValue(cdr.AnswerTime.Format(time.RFC3339)) case utils.USAGE: - return strconv.FormatFloat(storedCdr.Usage.Seconds(), 'f', -1, 64) + return strconv.FormatFloat(cdr.Usage.Seconds(), 'f', -1, 64) case utils.SUPPLIER: - return rsrFld.ParseValue(storedCdr.Supplier) + return rsrFld.ParseValue(cdr.Supplier) case utils.DISCONNECT_CAUSE: - return rsrFld.ParseValue(storedCdr.DisconnectCause) + return rsrFld.ParseValue(cdr.DisconnectCause) case utils.MEDI_RUNID: - return rsrFld.ParseValue(storedCdr.MediationRunId) - case utils.RATED_ACCOUNT: - return rsrFld.ParseValue(storedCdr.RatedAccount) - case utils.RATED_SUBJECT: - return rsrFld.ParseValue(storedCdr.RatedSubject) + return rsrFld.ParseValue(cdr.RunID) case utils.RATED_FLD: - return rsrFld.ParseValue(strconv.FormatBool(storedCdr.Rated)) + return rsrFld.ParseValue(strconv.FormatBool(cdr.Rated)) case utils.COST: - return rsrFld.ParseValue(strconv.FormatFloat(storedCdr.Cost, 'f', -1, 64)) // Recommended to use FormatCost + return rsrFld.ParseValue(strconv.FormatFloat(cdr.Cost, 'f', -1, 64)) // Recommended to use FormatCost case utils.COST_DETAILS: - return rsrFld.ParseValue(storedCdr.CostDetailsJson()) + return rsrFld.ParseValue(cdr.CostDetailsJson()) default: - return rsrFld.ParseValue(storedCdr.ExtraFields[rsrFld.Id]) + return rsrFld.ParseValue(cdr.ExtraFields[rsrFld.Id]) } } // Populates the field with id from value; strings are appended to original one -func (storedCdr *StoredCdr) ParseFieldValue(fieldId, fieldVal, timezone string) error { +func (cdr *CDR) ParseFieldValue(fieldId, fieldVal, timezone string) error { var err error switch fieldId { case utils.TOR: - storedCdr.TOR += fieldVal + cdr.ToR += fieldVal case utils.ACCID: - storedCdr.AccId += fieldVal + cdr.OriginID += fieldVal case utils.REQTYPE: - storedCdr.ReqType += fieldVal + cdr.RequestType += fieldVal case utils.DIRECTION: - storedCdr.Direction += fieldVal + cdr.Direction += fieldVal case utils.TENANT: - storedCdr.Tenant += fieldVal + cdr.Tenant += fieldVal case utils.CATEGORY: - storedCdr.Category += fieldVal + cdr.Category += fieldVal case utils.ACCOUNT: - storedCdr.Account += fieldVal + cdr.Account += fieldVal case utils.SUBJECT: - storedCdr.Subject += fieldVal + cdr.Subject += fieldVal case utils.DESTINATION: - storedCdr.Destination += fieldVal + cdr.Destination += fieldVal case utils.RATED_FLD: - storedCdr.Rated, _ = strconv.ParseBool(fieldVal) + cdr.Rated, _ = strconv.ParseBool(fieldVal) case utils.SETUP_TIME: - if storedCdr.SetupTime, err = utils.ParseTimeDetectLayout(fieldVal, timezone); err != nil { + 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 storedCdr.Pdd, err = utils.ParseDurationWithSecs(fieldVal); err != nil { + 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 storedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(fieldVal, timezone); err != nil { + 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()) } case utils.USAGE: - if storedCdr.Usage, err = utils.ParseDurationWithSecs(fieldVal); err != nil { + 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: - storedCdr.Supplier += fieldVal + cdr.Supplier += fieldVal case utils.DISCONNECT_CAUSE: - storedCdr.DisconnectCause += fieldVal + cdr.DisconnectCause += fieldVal case utils.COST: - if storedCdr.Cost, err = strconv.ParseFloat(fieldVal, 64); err != nil { + 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()) } default: // Extra fields will not match predefined so they all show up here - storedCdr.ExtraFields[fieldId] += fieldVal + cdr.ExtraFields[fieldId] += fieldVal } return nil } // concatenates values of multiple fields defined in template, used eg in CDR templates -func (storedCdr *StoredCdr) FieldsAsString(rsrFlds utils.RSRFields) string { +func (cdr *CDR) FieldsAsString(rsrFlds utils.RSRFields) string { var fldVal string for _, rsrFld := range rsrFlds { - fldVal += storedCdr.FieldAsString(rsrFld) + fldVal += cdr.FieldAsString(rsrFld) } return fldVal } -func (storedCdr *StoredCdr) PassesFieldFilter(fieldFilter *utils.RSRField) (bool, string) { +func (cdr *CDR) PassesFieldFilter(fieldFilter *utils.RSRField) (bool, string) { if fieldFilter == nil { return true, "" } - if fieldFilter.IsStatic() && storedCdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id}) == storedCdr.FieldAsString(fieldFilter) { - return true, storedCdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id}) + if fieldFilter.IsStatic() && cdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id}) == cdr.FieldAsString(fieldFilter) { + return true, cdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id}) } preparedFilter := &utils.RSRField{Id: fieldFilter.Id, RSRules: make([]*utils.ReSearchReplace, len(fieldFilter.RSRules))} // Reset rules so they do not point towards same structures as original fieldFilter for idx := range fieldFilter.RSRules { // Hardcode the template with maximum of 5 groups ordered preparedFilter.RSRules[idx] = &utils.ReSearchReplace{SearchRegexp: fieldFilter.RSRules[idx].SearchRegexp, ReplaceTemplate: utils.FILTER_REGEXP_TPL} } - preparedVal := storedCdr.FieldAsString(preparedFilter) - filteredValue := storedCdr.FieldAsString(fieldFilter) + preparedVal := cdr.FieldAsString(preparedFilter) + filteredValue := cdr.FieldAsString(fieldFilter) if preparedFilter.RegexpMatched() && (len(preparedVal) == 0 || preparedVal == filteredValue) { return true, filteredValue } return false, "" } -func (storedCdr *StoredCdr) AsStoredCdr(timezone string) *StoredCdr { - return storedCdr +func (cdr *CDR) AsStoredCdr(timezone string) *CDR { + return cdr } -func (storedCdr *StoredCdr) Clone() *StoredCdr { - clnCdr := *storedCdr - clnCdr.ExtraFields = make(map[string]string) - clnCdr.CostDetails = nil // Clean old reference - for k, v := range storedCdr.ExtraFields { - clnCdr.ExtraFields[k] = v - } - if storedCdr.CostDetails != nil { - cDetails := *storedCdr.CostDetails - clnCdr.CostDetails = &cDetails - } - return &clnCdr +func (cdr *CDR) Clone() *CDR { + var clnedCDR CDR + utils.Clone(cdr, &clnedCDR) + return &clnedCDR } // Ability to send the CgrCdr remotely to another CDR server, we do not include rating variables for now -func (storedCdr *StoredCdr) AsHttpForm() url.Values { +func (cdr *CDR) AsHttpForm() url.Values { v := url.Values{} - for fld, val := range storedCdr.ExtraFields { + for fld, val := range cdr.ExtraFields { v.Set(fld, val) } - v.Set(utils.TOR, storedCdr.TOR) - v.Set(utils.ACCID, storedCdr.AccId) - v.Set(utils.CDRHOST, storedCdr.CdrHost) - v.Set(utils.CDRSOURCE, storedCdr.CdrSource) - v.Set(utils.REQTYPE, storedCdr.ReqType) - v.Set(utils.DIRECTION, storedCdr.Direction) - v.Set(utils.TENANT, storedCdr.Tenant) - v.Set(utils.CATEGORY, storedCdr.Category) - v.Set(utils.ACCOUNT, storedCdr.Account) - v.Set(utils.SUBJECT, storedCdr.Subject) - v.Set(utils.DESTINATION, storedCdr.Destination) - v.Set(utils.SETUP_TIME, storedCdr.SetupTime.Format(time.RFC3339)) - v.Set(utils.PDD, storedCdr.FieldAsString(&utils.RSRField{Id: utils.PDD})) - v.Set(utils.ANSWER_TIME, storedCdr.AnswerTime.Format(time.RFC3339)) - v.Set(utils.USAGE, storedCdr.FormatUsage(utils.SECONDS)) - v.Set(utils.SUPPLIER, storedCdr.Supplier) - v.Set(utils.DISCONNECT_CAUSE, storedCdr.DisconnectCause) - if storedCdr.CostDetails != nil { - v.Set(utils.COST_DETAILS, storedCdr.CostDetailsJson()) + v.Set(utils.TOR, cdr.ToR) + v.Set(utils.ACCID, cdr.OriginID) + v.Set(utils.CDRHOST, cdr.OriginHost) + v.Set(utils.CDRSOURCE, cdr.Source) + v.Set(utils.REQTYPE, cdr.RequestType) + v.Set(utils.DIRECTION, cdr.Direction) + v.Set(utils.TENANT, cdr.Tenant) + v.Set(utils.CATEGORY, cdr.Category) + v.Set(utils.ACCOUNT, cdr.Account) + v.Set(utils.SUBJECT, cdr.Subject) + v.Set(utils.DESTINATION, cdr.Destination) + v.Set(utils.SETUP_TIME, cdr.SetupTime.Format(time.RFC3339)) + v.Set(utils.PDD, cdr.FieldAsString(&utils.RSRField{Id: utils.PDD})) + v.Set(utils.ANSWER_TIME, cdr.AnswerTime.Format(time.RFC3339)) + v.Set(utils.USAGE, cdr.FormatUsage(utils.SECONDS)) + v.Set(utils.SUPPLIER, cdr.Supplier) + v.Set(utils.DISCONNECT_CAUSE, cdr.DisconnectCause) + if cdr.CostDetails != nil { + v.Set(utils.COST_DETAILS, cdr.CostDetailsJson()) } return v } // Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored -func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, pddFld, +func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, PDDFld, answerTimeFld, durationFld, supplierFld, disconnectCauseFld, ratedFld, costFld *utils.RSRField, - extraFlds []*utils.RSRField, primaryMandatory bool, timezone string) (*StoredCdr, error) { - if reqTypeFld == nil { - reqTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT) + extraFlds []*utils.RSRField, primaryMandatory bool, timezone string) (*CDR, error) { + if RequestTypeFld == nil { + RequestTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } - if reqTypeFld.Id == utils.META_DEFAULT { - reqTypeFld.Id = utils.REQTYPE + if RequestTypeFld.Id == utils.META_DEFAULT { + RequestTypeFld.Id = utils.REQTYPE } if directionFld == nil { directionFld, _ = utils.NewRSRField(utils.META_DEFAULT) @@ -396,11 +378,11 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena if durationFld.Id == utils.META_DEFAULT { durationFld.Id = utils.USAGE } - if pddFld == nil { - pddFld, _ = utils.NewRSRField(utils.META_DEFAULT) + if PDDFld == nil { + PDDFld, _ = utils.NewRSRField(utils.META_DEFAULT) } - if pddFld.Id == utils.META_DEFAULT { - pddFld.Id = utils.PDD + if PDDFld.Id == utils.META_DEFAULT { + PDDFld.Id = utils.PDD } if supplierFld == nil { supplierFld, _ = utils.NewRSRField(utils.META_DEFAULT) @@ -427,75 +409,75 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena costFld.Id = utils.COST } var err error - frkStorCdr := new(StoredCdr) - frkStorCdr.CgrId = storedCdr.CgrId - frkStorCdr.TOR = storedCdr.TOR - frkStorCdr.MediationRunId = runId + frkStorCdr := new(CDR) + frkStorCdr.CGRID = cdr.CGRID + frkStorCdr.ToR = cdr.ToR + frkStorCdr.RunID = runId frkStorCdr.Cost = -1.0 // Default for non-rated CDR - frkStorCdr.AccId = storedCdr.AccId - frkStorCdr.CdrHost = storedCdr.CdrHost - frkStorCdr.CdrSource = storedCdr.CdrSource - frkStorCdr.ReqType = storedCdr.FieldAsString(reqTypeFld) - if primaryMandatory && len(frkStorCdr.ReqType) == 0 { - return nil, utils.NewErrMandatoryIeMissing(utils.REQTYPE, reqTypeFld.Id) + frkStorCdr.OriginID = cdr.OriginID + frkStorCdr.OriginHost = cdr.OriginHost + frkStorCdr.Source = cdr.Source + frkStorCdr.RequestType = cdr.FieldAsString(RequestTypeFld) + if primaryMandatory && len(frkStorCdr.RequestType) == 0 { + return nil, utils.NewErrMandatoryIeMissing(utils.REQTYPE, RequestTypeFld.Id) } - frkStorCdr.Direction = storedCdr.FieldAsString(directionFld) + frkStorCdr.Direction = cdr.FieldAsString(directionFld) if primaryMandatory && len(frkStorCdr.Direction) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.DIRECTION, directionFld.Id) } - frkStorCdr.Tenant = storedCdr.FieldAsString(tenantFld) + frkStorCdr.Tenant = cdr.FieldAsString(tenantFld) if primaryMandatory && len(frkStorCdr.Tenant) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.TENANT, tenantFld.Id) } - frkStorCdr.Category = storedCdr.FieldAsString(categFld) + frkStorCdr.Category = cdr.FieldAsString(categFld) if primaryMandatory && len(frkStorCdr.Category) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.CATEGORY, categFld.Id) } - frkStorCdr.Account = storedCdr.FieldAsString(accountFld) + frkStorCdr.Account = cdr.FieldAsString(accountFld) if primaryMandatory && len(frkStorCdr.Account) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ACCOUNT, accountFld.Id) } - frkStorCdr.Subject = storedCdr.FieldAsString(subjectFld) + frkStorCdr.Subject = cdr.FieldAsString(subjectFld) if primaryMandatory && len(frkStorCdr.Subject) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SUBJECT, subjectFld.Id) } - frkStorCdr.Destination = storedCdr.FieldAsString(destFld) - if primaryMandatory && len(frkStorCdr.Destination) == 0 && frkStorCdr.TOR == utils.VOICE { + frkStorCdr.Destination = cdr.FieldAsString(destFld) + if primaryMandatory && len(frkStorCdr.Destination) == 0 && frkStorCdr.ToR == utils.VOICE { return nil, utils.NewErrMandatoryIeMissing(utils.DESTINATION, destFld.Id) } - sTimeStr := storedCdr.FieldAsString(setupTimeFld) + sTimeStr := cdr.FieldAsString(setupTimeFld) if primaryMandatory && len(sTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SETUP_TIME, setupTimeFld.Id) } else if frkStorCdr.SetupTime, err = utils.ParseTimeDetectLayout(sTimeStr, timezone); err != nil { return nil, err } - aTimeStr := storedCdr.FieldAsString(answerTimeFld) + aTimeStr := cdr.FieldAsString(answerTimeFld) if primaryMandatory && len(aTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ANSWER_TIME, answerTimeFld.Id) } else if frkStorCdr.AnswerTime, err = utils.ParseTimeDetectLayout(aTimeStr, timezone); err != nil { return nil, err } - durStr := storedCdr.FieldAsString(durationFld) + 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 { return nil, err } - pddStr := storedCdr.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 { + 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 = storedCdr.FieldAsString(supplierFld) - frkStorCdr.DisconnectCause = storedCdr.FieldAsString(disconnectCauseFld) - ratedStr := storedCdr.FieldAsString(ratedFld) + 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) } else if frkStorCdr.Rated, err = strconv.ParseBool(ratedStr); err != nil { return nil, err } - costStr := storedCdr.FieldAsString(costFld) + costStr := cdr.FieldAsString(costFld) if primaryMandatory && len(costStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.COST, costFld.Id) } else if frkStorCdr.Cost, err = strconv.ParseFloat(costStr, 64); err != nil { @@ -503,226 +485,228 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena } frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds)) for _, fld := range extraFlds { - frkStorCdr.ExtraFields[fld.Id] = storedCdr.FieldAsString(fld) + frkStorCdr.ExtraFields[fld.Id] = cdr.FieldAsString(fld) } return frkStorCdr, nil } -func (storedCdr *StoredCdr) AsExternalCdr() *ExternalCdr { - return &ExternalCdr{CgrId: storedCdr.CgrId, - OrderId: storedCdr.OrderId, - TOR: storedCdr.TOR, - AccId: storedCdr.AccId, - CdrHost: storedCdr.CdrHost, - CdrSource: storedCdr.CdrSource, - ReqType: storedCdr.ReqType, - Direction: storedCdr.Direction, - Tenant: storedCdr.Tenant, - Category: storedCdr.Category, - Account: storedCdr.Account, - Subject: storedCdr.Subject, - Destination: storedCdr.Destination, - SetupTime: storedCdr.SetupTime.Format(time.RFC3339), - AnswerTime: storedCdr.AnswerTime.Format(time.RFC3339), - Usage: storedCdr.FormatUsage(utils.SECONDS), - Pdd: storedCdr.FieldAsString(&utils.RSRField{Id: utils.PDD}), - Supplier: storedCdr.Supplier, - DisconnectCause: storedCdr.DisconnectCause, - ExtraFields: storedCdr.ExtraFields, - MediationRunId: storedCdr.MediationRunId, - RatedAccount: storedCdr.RatedAccount, - RatedSubject: storedCdr.RatedSubject, - Cost: storedCdr.Cost, - CostDetails: storedCdr.CostDetailsJson(), +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, } } // Implementation of Event interface, used in tests -func (storedCdr *StoredCdr) AsEvent(ignored string) Event { - return Event(storedCdr) +func (cdr *CDR) AsEvent(ignored string) Event { + return Event(cdr) } -func (storedCdr *StoredCdr) ComputeLcr() bool { +func (cdr *CDR) ComputeLcr() bool { return false } -func (storedCdr *StoredCdr) GetName() string { - return storedCdr.CdrSource +func (cdr *CDR) GetName() string { + return cdr.Source } -func (storedCdr *StoredCdr) GetCgrId(timezone string) string { - return storedCdr.CgrId +func (cdr *CDR) GetCgrId(timezone string) string { + return cdr.CGRID } -func (storedCdr *StoredCdr) GetUUID() string { - return storedCdr.AccId +func (cdr *CDR) GetUUID() string { + return cdr.OriginID } -func (storedCdr *StoredCdr) GetSessionIds() []string { - return []string{storedCdr.GetUUID()} +func (cdr *CDR) GetSessionIds() []string { + return []string{cdr.GetUUID()} } -func (storedCdr *StoredCdr) GetDirection(fieldName string) string { +func (cdr *CDR) GetDirection(fieldName string) string { if utils.IsSliceMember([]string{utils.DIRECTION, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Direction + return cdr.Direction } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetSubject(fieldName string) string { +func (cdr *CDR) GetSubject(fieldName string) string { if utils.IsSliceMember([]string{utils.SUBJECT, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Subject + return cdr.Subject } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetAccount(fieldName string) string { +func (cdr *CDR) GetAccount(fieldName string) string { if utils.IsSliceMember([]string{utils.ACCOUNT, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Account + return cdr.Account } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetDestination(fieldName string) string { +func (cdr *CDR) GetDestination(fieldName string) string { if utils.IsSliceMember([]string{utils.DESTINATION, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Destination + return cdr.Destination } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetCallDestNr(fieldName string) string { +func (cdr *CDR) GetCallDestNr(fieldName string) string { if utils.IsSliceMember([]string{utils.DESTINATION, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Destination + return cdr.Destination } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetCategory(fieldName string) string { +func (cdr *CDR) GetCategory(fieldName string) string { if utils.IsSliceMember([]string{utils.CATEGORY, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Category + return cdr.Category } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetTenant(fieldName string) string { +func (cdr *CDR) GetTenant(fieldName string) string { if utils.IsSliceMember([]string{utils.TENANT, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Tenant + return cdr.Tenant } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetReqType(fieldName string) string { +func (cdr *CDR) GetReqType(fieldName string) string { if utils.IsSliceMember([]string{utils.REQTYPE, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.ReqType + return cdr.RequestType } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetSetupTime(fieldName, timezone string) (time.Time, error) { +func (cdr *CDR) GetSetupTime(fieldName, timezone string) (time.Time, error) { if utils.IsSliceMember([]string{utils.SETUP_TIME, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.SetupTime, nil + return cdr.SetupTime, nil } var sTimeVal string if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value sTimeVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { - sTimeVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + sTimeVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } return utils.ParseTimeDetectLayout(sTimeVal, timezone) } -func (storedCdr *StoredCdr) GetAnswerTime(fieldName, timezone string) (time.Time, error) { +func (cdr *CDR) GetAnswerTime(fieldName, timezone string) (time.Time, error) { if utils.IsSliceMember([]string{utils.ANSWER_TIME, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.AnswerTime, nil + return cdr.AnswerTime, nil } var aTimeVal string if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value aTimeVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { - aTimeVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + aTimeVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } return utils.ParseTimeDetectLayout(aTimeVal, timezone) } -func (storedCdr *StoredCdr) GetEndTime(fieldName, timezone string) (time.Time, error) { - return storedCdr.AnswerTime.Add(storedCdr.Usage), nil +func (cdr *CDR) GetEndTime(fieldName, timezone string) (time.Time, error) { + return cdr.AnswerTime.Add(cdr.Usage), nil } -func (storedCdr *StoredCdr) GetDuration(fieldName string) (time.Duration, error) { +func (cdr *CDR) GetDuration(fieldName string) (time.Duration, error) { if utils.IsSliceMember([]string{utils.USAGE, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Usage, nil + return cdr.Usage, nil } var durVal string if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value durVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { - durVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + durVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } return utils.ParseDurationWithSecs(durVal) } -func (storedCdr *StoredCdr) GetPdd(fieldName string) (time.Duration, error) { +func (cdr *CDR) GetPdd(fieldName string) (time.Duration, error) { if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Pdd, nil + return cdr.PDD, nil } - var pddVal string + var PDDVal string if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value - pddVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] + PDDVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { - pddVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + PDDVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } - return utils.ParseDurationWithSecs(pddVal) + return utils.ParseDurationWithSecs(PDDVal) } -func (storedCdr *StoredCdr) GetSupplier(fieldName string) string { +func (cdr *CDR) GetSupplier(fieldName string) string { if utils.IsSliceMember([]string{utils.SUPPLIER, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.Supplier + return cdr.Supplier } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetDisconnectCause(fieldName string) string { +func (cdr *CDR) GetDisconnectCause(fieldName string) string { if utils.IsSliceMember([]string{utils.DISCONNECT_CAUSE, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.DisconnectCause + return cdr.DisconnectCause } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetOriginatorIP(fieldName string) string { +func (cdr *CDR) GetOriginatorIP(fieldName string) string { if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT, ""}, fieldName) { - return storedCdr.CdrHost + return cdr.OriginHost } - return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) + return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } -func (storedCdr *StoredCdr) GetExtraFields() map[string]string { - return storedCdr.ExtraFields +func (cdr *CDR) GetExtraFields() map[string]string { + return cdr.ExtraFields } -func (storedCdr *StoredCdr) MissingParameter(timezone string) bool { - return len(storedCdr.AccId) == 0 || - len(storedCdr.Category) == 0 || - len(storedCdr.Tenant) == 0 || - len(storedCdr.Account) == 0 || - len(storedCdr.Destination) == 0 +func (cdr *CDR) MissingParameter(timezone string) bool { + return len(cdr.OriginID) == 0 || + len(cdr.Category) == 0 || + len(cdr.Tenant) == 0 || + len(cdr.Account) == 0 || + len(cdr.Destination) == 0 } -func (storedCdr *StoredCdr) ParseEventValue(rsrFld *utils.RSRField, timezone string) string { - return storedCdr.FieldAsString(rsrFld) +func (cdr *CDR) ParseEventValue(rsrFld *utils.RSRField, timezone string) string { + return cdr.FieldAsString(rsrFld) } -func (storedCdr *StoredCdr) String() string { - mrsh, _ := json.Marshal(storedCdr) +func (cdr *CDR) String() string { + mrsh, _ := json.Marshal(cdr) return string(mrsh) } -type ExternalCdr struct { - CgrId string - OrderId int64 - TOR string - AccId string - CdrHost string - CdrSource string - ReqType string +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 @@ -730,24 +714,23 @@ type ExternalCdr struct { Subject string Destination string SetupTime string + PDD string AnswerTime string Usage string - Pdd string Supplier string DisconnectCause string ExtraFields map[string]string - MediationRunId string - RatedAccount string - RatedSubject 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 - ReqType string + ToR string + RequestType string Direction string Tenant string Category string @@ -760,33 +743,32 @@ type UsageRecord struct { ExtraFields map[string]string } -func (self *UsageRecord) AsStoredCdr(timezone string) (*StoredCdr, error) { +func (self *UsageRecord) AsStoredCdr(timezone string) (*CDR, error) { var err error - storedCdr := &StoredCdr{CgrId: self.GetId(), TOR: self.TOR, ReqType: self.ReqType, Direction: self.Direction, Tenant: self.Tenant, Category: self.Category, - Account: self.Account, Subject: self.Subject, Destination: self.Destination} - if storedCdr.SetupTime, err = utils.ParseTimeDetectLayout(self.SetupTime, timezone); err != nil { + 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} + if cdr.SetupTime, err = utils.ParseTimeDetectLayout(self.SetupTime, timezone); err != nil { return nil, err } - if storedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(self.AnswerTime, timezone); err != nil { + if cdr.AnswerTime, err = utils.ParseTimeDetectLayout(self.AnswerTime, timezone); err != nil { return nil, err } - if storedCdr.Usage, err = utils.ParseDurationWithSecs(self.Usage); err != nil { + if cdr.Usage, err = utils.ParseDurationWithSecs(self.Usage); err != nil { return nil, err } if self.ExtraFields != nil { - storedCdr.ExtraFields = make(map[string]string) + cdr.ExtraFields = make(map[string]string) } for k, v := range self.ExtraFields { - storedCdr.ExtraFields[k] = v + cdr.ExtraFields[k] = v } - return storedCdr, nil + return cdr, nil } func (self *UsageRecord) AsCallDescriptor(timezone string) (*CallDescriptor, error) { var err error cd := &CallDescriptor{ CgrId: self.GetId(), - TOR: self.TOR, + TOR: self.ToR, Direction: self.Direction, Tenant: self.Tenant, Category: self.Category, @@ -816,5 +798,5 @@ func (self *UsageRecord) AsCallDescriptor(timezone string) (*CallDescriptor, err } func (self *UsageRecord) GetId() string { - return utils.Sha1(self.TOR, self.ReqType, 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.Direction, self.Tenant, self.Category, self.Account, self.Subject, self.Destination, self.SetupTime, self.AnswerTime, self.Usage) } diff --git a/engine/storedcdr_local_test.go b/engine/cdr_local_test.go similarity index 77% rename from engine/storedcdr_local_test.go rename to engine/cdr_local_test.go index 78598d20c..823e8f6d5 100644 --- a/engine/storedcdr_local_test.go +++ b/engine/cdr_local_test.go @@ -34,13 +34,13 @@ func TestHttpJsonPost(t *testing.T) { if !*testLocal { return } - cdrOut := &ExternalCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", - CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + 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", 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(), - MediationRunId: utils.DEFAULT_RUNID, - Usage: "0.00000001", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, + RunID: utils.DEFAULT_RUNID, + Usage: "0.00000001", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if _, err := utils.HttpJsonPost("http://localhost:8000", false, cdrOut); err == nil { t.Error(err) diff --git a/engine/storedcdr_test.go b/engine/cdr_test.go similarity index 66% rename from engine/storedcdr_test.go rename to engine/cdr_test.go index 670c3bdee..013e0c8dc 100644 --- a/engine/storedcdr_test.go +++ b/engine/cdr_test.go @@ -26,38 +26,38 @@ import ( "github.com/cgrates/cgrates/utils" ) -func TestStoredCdrInterfaces(t *testing.T) { - storedCdr := new(StoredCdr) - var _ RawCdr = storedCdr - var _ Event = storedCdr +func TestCDRInterfaces(t *testing.T) { + CDR := new(CDR) + var _ RawCdr = CDR + var _ Event = CDR } -func TestNewStoredCdrFromExternalCdr(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, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +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", - SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", MediationRunId: utils.DEFAULT_RUNID, - Usage: "0.00000001", Pdd: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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, } - eStorCdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + 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), MediationRunId: 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, RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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, } - if storedCdr, err := NewStoredCdrFromExternalCdr(extCdr, ""); err != nil { + if CDR, err := NewCDRFromExternalCDR(extCdr, ""); err != nil { t.Error(err) - } else if !reflect.DeepEqual(eStorCdr, storedCdr) { - t.Errorf("Expected: %+v, received: %+v", eStorCdr, storedCdr) + } else if !reflect.DeepEqual(eStorCdr, CDR) { + t.Errorf("Expected: %+v, received: %+v", eStorCdr, CDR) } } -func TestStoredCdrClone(t *testing.T) { - storCdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +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), MediationRunId: 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, RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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, } if clnStorCdr := storCdr.Clone(); !reflect.DeepEqual(storCdr, clnStorCdr) { t.Errorf("Expecting: %+v, received: %+v", storCdr, clnStorCdr) @@ -65,20 +65,21 @@ func TestStoredCdrClone(t *testing.T) { } func TestFieldAsString(t *testing.T) { - cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, Pdd: time.Duration(5) * time.Second, Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", + 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", + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, + Cost: 1.01, } - if cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CgrId || + if cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CGRID || cdr.FieldAsString(&utils.RSRField{Id: utils.ORDERID}) != "123" || cdr.FieldAsString(&utils.RSRField{Id: utils.TOR}) != utils.VOICE || - cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.AccId || - cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.CdrHost || - cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.CdrSource || - cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.ReqType || + cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.OriginID || + 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 || @@ -89,21 +90,19 @@ func TestFieldAsString(t *testing.T) { 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.MediationRunId || + cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.RunID || cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01" || - cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_ACCOUNT}) != "dan" || - cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_SUBJECT}) != "dans" || cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"] || cdr.FieldAsString(&utils.RSRField{Id: "fieldextr2"}) != cdr.ExtraFields["fieldextr2"] || cdr.FieldAsString(&utils.RSRField{Id: "dummy_field"}) != "" { t.Error("Unexpected filed value received", - cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CgrId, + cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CGRID, cdr.FieldAsString(&utils.RSRField{Id: utils.ORDERID}) != "123", cdr.FieldAsString(&utils.RSRField{Id: utils.TOR}) != utils.VOICE, - cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.AccId, - cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.CdrHost, - cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.CdrSource, - cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.ReqType, + cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.OriginID, + 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, @@ -114,9 +113,7 @@ func TestFieldAsString(t *testing.T) { 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.MediationRunId, - cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_ACCOUNT}) != "dan", - cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_SUBJECT}) != "dans", + 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"], cdr.FieldAsString(&utils.RSRField{Id: "fieldextr2"}) != cdr.ExtraFields["fieldextr2"], @@ -125,12 +122,12 @@ func TestFieldAsString(t *testing.T) { } func TestFieldsAsString(t *testing.T) { - cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + 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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, Pdd: time.Duration(5) * time.Second, Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", + 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", + 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 { @@ -139,10 +136,10 @@ func TestFieldsAsString(t *testing.T) { } func TestPassesFieldFilter(t *testing.T) { - cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", + 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), MediationRunId: utils.DEFAULT_RUNID, + 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, } if pass, _ := cdr.PassesFieldFilter(nil); !pass { @@ -168,7 +165,7 @@ func TestPassesFieldFilter(t *testing.T) { if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Passing filter") } - torFltr, _ := utils.NewRSRField(`^TOR::*voice/`) + torFltr, _ := utils.NewRSRField(`^ToR::*voice/`) if pass, _ := cdr.PassesFieldFilter(torFltr); !pass { t.Error("Not passing filter") } @@ -183,7 +180,7 @@ func TestPassesFieldFilter(t *testing.T) { } func TestPassesFieldFilterDn1(t *testing.T) { - cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem0005", + cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem0005", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } acntPrefxFltr, _ := utils.NewRSRField(`~Account:s/^\w+[shmp]\d{4}$//`) @@ -191,13 +188,13 @@ func TestPassesFieldFilterDn1(t *testing.T) { t.Error("Not passing valid filter") } - cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem00005", + cdr = &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem00005", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } - cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0402129281", + cdr = &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0402129281", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^0\d{9}$//`) @@ -208,13 +205,13 @@ func TestPassesFieldFilterDn1(t *testing.T) { if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } - cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "04021292812", + cdr = &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "04021292812", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } - cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0162447222", + cdr = &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0162447222", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if acntPrefxFltr, err := utils.NewRSRField(`~Account:s/^0\d{9}$//`); err != nil { @@ -234,11 +231,11 @@ func TestPassesFieldFilterDn1(t *testing.T) { } func TestUsageMultiply(t *testing.T) { - cdr := StoredCdr{Usage: time.Duration(10) * time.Second} + cdr := CDR{Usage: time.Duration(10) * time.Second} if cdr.UsageMultiply(1024.0, 0); cdr.Usage != time.Duration(10240)*time.Second { t.Errorf("Unexpected usage after multiply: %v", cdr.Usage.Nanoseconds()) } - cdr = StoredCdr{Usage: time.Duration(10240) * time.Second} // Simulate conversion back, gives out a bit odd result but this can be rounded on export + cdr = CDR{Usage: time.Duration(10240) * time.Second} // Simulate conversion back, gives out a bit odd result but this can be rounded on export expectDuration, _ := time.ParseDuration("10.000005120s") if cdr.UsageMultiply(0.000976563, 0); cdr.Usage != expectDuration { t.Errorf("Unexpected usage after multiply: %v", cdr.Usage.Nanoseconds()) @@ -246,22 +243,22 @@ func TestUsageMultiply(t *testing.T) { } func TestCostMultiply(t *testing.T) { - cdr := StoredCdr{Cost: 1.01} + cdr := CDR{Cost: 1.01} if cdr.CostMultiply(1.19, 4); cdr.Cost != 1.2019 { t.Errorf("Unexpected cost after multiply: %v", cdr.Cost) } - cdr = StoredCdr{Cost: 1.01} + cdr = CDR{Cost: 1.01} if cdr.CostMultiply(1000, 0); cdr.Cost != 1010 { t.Errorf("Unexpected cost after multiply: %v", cdr.Cost) } } func TestFormatCost(t *testing.T) { - cdr := StoredCdr{Cost: 1.01} + cdr := CDR{Cost: 1.01} if cdr.FormatCost(0, 4) != "1.0100" { t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4)) } - cdr = StoredCdr{Cost: 1.01001} + cdr = CDR{Cost: 1.01001} if cdr.FormatCost(0, 4) != "1.0100" { t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4)) } @@ -277,34 +274,34 @@ func TestFormatCost(t *testing.T) { } func TestFormatUsage(t *testing.T) { - cdr := StoredCdr{Usage: time.Duration(10) * time.Second} + cdr := CDR{Usage: time.Duration(10) * time.Second} if cdr.FormatUsage(utils.SECONDS) != "10" { t.Error("Wrong usage format: ", cdr.FormatUsage(utils.SECONDS)) } if cdr.FormatUsage("default") != "10" { t.Error("Wrong usage format: ", cdr.FormatUsage("default")) } - cdr = StoredCdr{TOR: utils.DATA, Usage: time.Duration(1640113000000000)} + cdr = CDR{ToR: utils.DATA, Usage: time.Duration(1640113000000000)} if cdr.FormatUsage("default") != "1640113" { t.Error("Wrong usage format: ", cdr.FormatUsage("default")) } - cdr = StoredCdr{Usage: time.Duration(2) * time.Millisecond} + cdr = CDR{Usage: time.Duration(2) * time.Millisecond} if cdr.FormatUsage("default") != "0.002" { t.Error("Wrong usage format: ", cdr.FormatUsage("default")) } - cdr = StoredCdr{Usage: time.Duration(1002) * time.Millisecond} + cdr = CDR{Usage: time.Duration(1002) * time.Millisecond} if cdr.FormatUsage("default") != "1.002" { t.Error("Wrong usage format: ", cdr.FormatUsage("default")) } } -func TestStoredCdrAsHttpForm(t *testing.T) { - storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +func TestCDRAsHttpForm(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), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: 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), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RatedSubject: "dans", Cost: 1.01, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } cdrForm := storCdr.AsHttpForm() if cdrForm.Get(utils.TOR) != utils.VOICE { @@ -360,13 +357,14 @@ func TestStoredCdrAsHttpForm(t *testing.T) { } } -func TestStoredCdrForkCdr(t *testing.T) { - storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +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), MediationRunId: 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, RatedSubject: "dans"} + 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}, &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}, @@ -375,21 +373,21 @@ func TestStoredCdrForkCdr(t *testing.T) { if err != nil { t.Error("Unexpected error received", err) } - expctSplRatedCdr := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, + 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), + 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"}, - MediationRunId: "sample_run1", Rated: false, Cost: 1.01} + RunID: "sample_run1", Rated: false, Cost: 1.01} if !reflect.DeepEqual(expctSplRatedCdr, rtSampleCdrOut) { t.Errorf("Expected: %v, received: %v", expctSplRatedCdr, rtSampleCdrOut) } } -func TestStoredCdrForkCdrStaticVals(t *testing.T) { - storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +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", 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), MediationRunId: 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), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } rsrStPostpaid, _ := utils.NewRSRField("^" + utils.META_POSTPAID) @@ -403,20 +401,20 @@ func TestStoredCdrForkCdrStaticVals(t *testing.T) { rsrStDur, _ := utils.NewRSRField("^12s") rsrStSuppl, _ := utils.NewRSRField("^supplier1") rsrStDCause, _ := utils.NewRSRField("^HANGUP_COMPLETE") - rsrPdd, _ := utils.NewRSRField("^3") + 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, "") + rsrStST, rsrPDD, rsrStAT, rsrStDur, rsrStSuppl, rsrStDCause, rsrStRated, rsrStCost, []*utils.RSRField{}, true, "") if err != nil { t.Error("Unexpected error received", err) } - expctRatedCdr2 := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, + 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", 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, + 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, - ExtraFields: map[string]string{}, MediationRunId: "wholesale_run"} + ExtraFields: map[string]string{}, RunID: "wholesale_run"} if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) { t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2) } @@ -430,19 +428,19 @@ func TestStoredCdrForkCdrStaticVals(t *testing.T) { } } -func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) { - storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", +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), MediationRunId: utils.DEFAULT_RUNID, - Usage: time.Duration(10) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL3", + 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, } - expctCdr := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, + 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"}, MediationRunId: "wholesale_run"} + 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}, @@ -464,32 +462,30 @@ func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) { } } -func TestStoredCdrAsExternalCdr(t *testing.T) { - storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", +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", 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), MediationRunId: 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, RatedAccount: "dan", RatedSubject: "dans", - } - expectOutCdr := &ExternalCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: 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), 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", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", - SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", MediationRunId: utils.DEFAULT_RUNID, - Usage: "0.00000001", Pdd: "7", Supplier: "SUPPL1", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", - } - if cdrOut := storCdr.AsExternalCdr(); !reflect.DeepEqual(expectOutCdr, cdrOut) { + 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"} + if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) } } -func TestStoredCdrEventFields(t *testing.T) { - cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dans", +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), - MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, Supplier: "suppl1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"} + 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} if ev := cdr.AsEvent(""); ev != Event(cdr) { t.Error("Received: ", ev) @@ -542,7 +538,7 @@ func TestStoredCdrEventFields(t *testing.T) { if suppl := cdr.GetSupplier(utils.META_DEFAULT); suppl != cdr.Supplier { t.Error("Received: ", suppl) } - if res := cdr.GetOriginatorIP(utils.META_DEFAULT); res != cdr.CdrHost { + if res := cdr.GetOriginatorIP(utils.META_DEFAULT); res != cdr.OriginHost { t.Error("Received: ", res) } if extraFlds := cdr.GetExtraFields(); !reflect.DeepEqual(cdr.ExtraFields, extraFlds) { @@ -550,29 +546,27 @@ func TestStoredCdrEventFields(t *testing.T) { } } -func TesUsageReqAsStoredCdr(t *testing.T) { - setupReq := &UsageRecord{TOR: utils.VOICE, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", +func TesUsageReqAsCDR(t *testing.T) { + setupReq := &UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: "*out", 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 := &StoredCdr{TOR: utils.VOICE, ReqType: utils.META_RATED, Direction: "*out", + 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)} - if storedCdr, err := setupReq.AsStoredCdr(""); err != nil { + if CDR, err := setupReq.AsStoredCdr(""); err != nil { t.Error(err) - } else if !reflect.DeepEqual(eStorCdr, storedCdr) { - t.Errorf("Expected: %+v, received: %+v", eStorCdr, storedCdr) + } else if !reflect.DeepEqual(eStorCdr, CDR) { + t.Errorf("Expected: %+v, received: %+v", eStorCdr, CDR) } } func TestUsageReqAsCD(t *testing.T) { - req := &UsageRecord{TOR: utils.VOICE, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", + req := &UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: "*out", 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", } - 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))} + 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))} if cd, err := req.AsCallDescriptor(""); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCD, cd) { diff --git a/engine/cdrs.go b/engine/cdrs.go index 6eeeb0c14..8b603111d 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -107,8 +107,8 @@ func (self *CdrServer) RegisterHandlersToServer(server *utils.Server) { server.RegisterHttpFunc("/freeswitch_json", fsCdrHandler) } -func (self *CdrServer) ProcessCdr(cdr *StoredCdr, reply *string) error { - cacheKey := "ProcessCdr" + cdr.CgrId +func (self *CdrServer) ProcessCdr(cdr *CDR, reply *string) error { + cacheKey := "ProcessCdr" + cdr.CGRID if item, err := self.getCache().Get(cacheKey); err == nil && item != nil { *reply = item.Value.(string) return item.Err @@ -123,17 +123,17 @@ func (self *CdrServer) ProcessCdr(cdr *StoredCdr, reply *string) error { } // RPC method, used to internally process CDR -func (self *CdrServer) LocalProcessCdr(cdr *StoredCdr) error { +func (self *CdrServer) LocalProcessCdr(cdr *CDR) error { return self.processCdr(cdr) } // RPC method, used to process external CDRs -func (self *CdrServer) ProcessExternalCdr(cdr *ExternalCdr) error { - storedCdr, err := NewStoredCdrFromExternalCdr(cdr, self.cgrCfg.DefaultTimezone) +func (self *CdrServer) ProcessExternalCdr(eCDR *ExternalCDR) error { + cdr, err := NewCDRFromExternalCDR(eCDR, self.cgrCfg.DefaultTimezone) if err != nil { return err } - return self.processCdr(storedCdr) + return self.processCdr(cdr) } func (self *CdrServer) LogCallCost(ccl *CallCostLog, reply *string) error { @@ -155,44 +155,27 @@ func (self *CdrServer) LogCallCost(ccl *CallCostLog, reply *string) error { func (self *CdrServer) LocalLogCallCost(ccl *CallCostLog) error { if ccl.CheckDuplicate { _, err := self.guard.Guard(func() (interface{}, error) { - cc, err := self.cdrDb.GetCallCostLog(ccl.CgrId, ccl.Source, ccl.RunId) + cc, err := self.cdrDb.GetCallCostLog(ccl.CgrId, ccl.RunId) if err != nil && err != gorm.RecordNotFound && err != mgov2.ErrNotFound { return nil, err } if cc != nil { return nil, utils.ErrExists } - return nil, self.cdrDb.LogCallCost(ccl.CgrId, ccl.Source, ccl.RunId, ccl.CallCost) + return nil, self.cdrDb.LogCallCost(ccl.CgrId, ccl.RunId, ccl.Source, ccl.CallCost) }, 0, ccl.CgrId) return err } - return self.cdrDb.LogCallCost(ccl.CgrId, ccl.Source, ccl.RunId, ccl.CallCost) + return self.cdrDb.LogCallCost(ccl.CgrId, ccl.RunId, ccl.Source, ccl.CallCost) } // Called by rate/re-rate API -func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes, ratedAccounts, ratedSubjects []string, - orderIdStart, orderIdEnd int64, timeStart, timeEnd time.Time, rerateErrors, rerateRated, sendToStats bool) error { - var costStart, costEnd *float64 - if rerateErrors { - costStart = utils.Float64Pointer(-1.0) - if !rerateRated { - costEnd = utils.Float64Pointer(0.0) - } - } else if rerateRated { - costStart = utils.Float64Pointer(0.0) - } - cdrs, _, err := self.cdrDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: cgrIds, RunIds: runIds, Tors: tors, CdrHosts: cdrHosts, CdrSources: cdrSources, - ReqTypes: reqTypes, Directions: directions, Tenants: tenants, Categories: categories, Accounts: accounts, - Subjects: subjects, DestPrefixes: destPrefixes, RatedAccounts: ratedAccounts, RatedSubjects: ratedSubjects, - OrderIdStart: orderIdStart, OrderIdEnd: orderIdEnd, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, - MinCost: costStart, MaxCost: costEnd}) +func (self *CdrServer) RateCDRs(cdrFltr *utils.CDRsFilter, sendToStats bool) error { + cdrs, _, err := self.cdrDb.GetCDRs(cdrFltr) if err != nil { return err } for _, cdr := range cdrs { - if cdr.MediationRunId == "" { // raw CDRs which were not calculated before - cdr.MediationRunId = utils.META_DEFAULT - } // replace aliases for cases they were loaded after CDR received if err := LoadAlias(&AttrMatchingAlias{ Destination: cdr.Destination, @@ -209,7 +192,7 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { return err } - if err := self.rateStoreStatsReplicate(cdr); err != nil { + if err := self.rateStoreStatsReplicate(cdr, sendToStats); err != nil { utils.Logger.Err(fmt.Sprintf(" Processing CDR %+v, got error: %s", cdr, err.Error())) } } @@ -217,79 +200,66 @@ func (self *CdrServer) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqT } // Returns error if not able to properly store the CDR, mediation is async since we can always recover offline -func (self *CdrServer) processCdr(storedCdr *StoredCdr) (err error) { - if storedCdr.Direction == "" { - storedCdr.Direction = utils.OUT +func (self *CdrServer) processCdr(cdr *CDR) (err error) { + if cdr.Direction == "" { + cdr.Direction = utils.OUT } - if storedCdr.ReqType == "" { - storedCdr.ReqType = self.cgrCfg.DefaultReqType + if cdr.RequestType == "" { + cdr.RequestType = self.cgrCfg.DefaultReqType } - if storedCdr.Tenant == "" { - storedCdr.Tenant = self.cgrCfg.DefaultTenant + if cdr.Tenant == "" { + cdr.Tenant = self.cgrCfg.DefaultTenant } - if storedCdr.Category == "" { - storedCdr.Category = self.cgrCfg.DefaultCategory + if cdr.Category == "" { + cdr.Category = self.cgrCfg.DefaultCategory } - if storedCdr.Subject == "" { // Use account information as rating subject if missing - storedCdr.Subject = storedCdr.Account + if cdr.Subject == "" { // Use account information as rating subject if missing + cdr.Subject = cdr.Account } - // replace aliases - if err := LoadAlias(&AttrMatchingAlias{ - Destination: storedCdr.Destination, - Direction: storedCdr.Direction, - Tenant: storedCdr.Tenant, - Category: storedCdr.Category, - Account: storedCdr.Account, - Subject: storedCdr.Subject, - Context: utils.ALIAS_CONTEXT_RATING, - }, storedCdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { - return err - } - // replace user profile fields - if err := LoadUserProfile(storedCdr, utils.EXTRA_FIELDS); err != nil { - return err + if !cdr.Rated { + cdr.RunID = utils.MetaRaw } if self.cgrCfg.CDRSStoreCdrs { // Store RawCDRs, this we do sync so we can reply with the status - if err := self.cdrDb.SetCdr(storedCdr); err != nil { // Only original CDR stored in primary table, no derived - utils.Logger.Err(fmt.Sprintf(" Storing primary CDR %+v, got error: %s", storedCdr, err.Error())) + if err := self.cdrDb.SetCDR(cdr, false); err != nil { // Only original CDR stored in primary table, no derived + utils.Logger.Err(fmt.Sprintf(" Storing primary CDR %+v, got error: %s", cdr, err.Error())) return err // Error is propagated back and we don't continue processing the CDR if we cannot store it } - } - go self.deriveRateStoreStatsReplicate(storedCdr) + go self.deriveRateStoreStatsReplicate(cdr) return nil } // Returns error if not able to properly store the CDR, mediation is async since we can always recover offline -func (self *CdrServer) deriveRateStoreStatsReplicate(storedCdr *StoredCdr) error { - cdrRuns, err := self.deriveCdrs(storedCdr) +func (self *CdrServer) deriveRateStoreStatsReplicate(cdr *CDR) error { + cdrRuns, err := self.deriveCdrs(cdr) if err != nil { return err } - for _, cdr := range cdrRuns { - if err := self.rateStoreStatsReplicate(cdr); err != nil { + for _, cdrRun := range cdrRuns { + if err := self.rateStoreStatsReplicate(cdrRun, true); err != nil { return err } } return nil } -func (self *CdrServer) rateStoreStatsReplicate(cdr *StoredCdr) error { - if cdr.MediationRunId != utils.META_DEFAULT { // Process Aliases and Users for derived CDRs - if err := LoadAlias(&AttrMatchingAlias{ - Destination: cdr.Destination, - Direction: cdr.Direction, - Tenant: cdr.Tenant, - Category: cdr.Category, - Account: cdr.Account, - Subject: cdr.Subject, - Context: utils.ALIAS_CONTEXT_RATING, - }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { - return err - } - if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { - return err - } +func (self *CdrServer) rateStoreStatsReplicate(cdr *CDR, sendToStats bool) error { + if cdr.RunID == utils.MetaRaw { // Overwrite *raw with *default for rating + cdr.RunID = utils.META_DEFAULT + } + if err := LoadAlias(&AttrMatchingAlias{ + Destination: cdr.Destination, + Direction: cdr.Direction, + Tenant: cdr.Tenant, + Category: cdr.Category, + Account: cdr.Account, + Subject: cdr.Subject, + Context: utils.ALIAS_CONTEXT_RATING, + }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { + return err + } + if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { + return err } // Rate CDR if self.client != nil && !cdr.Rated { @@ -298,7 +268,7 @@ func (self *CdrServer) rateStoreStatsReplicate(cdr *StoredCdr) error { cdr.ExtraInfo = err.Error() } } - if cdr.MediationRunId == utils.META_SURETAX { // Request should be processed by SureTax + if cdr.RunID == utils.META_SURETAX { // Request should be processed by SureTax if err := SureTaxProcessCdr(cdr); err != nil { cdr.Cost = -1.0 cdr.ExtraInfo = err.Error() // Something failed, write the error in the ExtraInfo @@ -306,18 +276,12 @@ func (self *CdrServer) rateStoreStatsReplicate(cdr *StoredCdr) error { } if self.cgrCfg.CDRSStoreCdrs { // Store CDRs // Store RatedCDR - if err := self.cdrDb.SetRatedCdr(cdr); err != nil { + if err := self.cdrDb.SetCDR(cdr, true); err != nil { utils.Logger.Err(fmt.Sprintf(" Storing rated CDR %+v, got error: %s", cdr, err.Error())) } - // Store CostDetails - if cdr.Rated || utils.IsSliceMember([]string{utils.RATED, utils.META_RATED}, cdr.ReqType) { // Account related CDRs are saved automatically, so save the others here if requested - if err := self.cdrDb.LogCallCost(cdr.CgrId, utils.CDRS_SOURCE, cdr.MediationRunId, cdr.CostDetails); err != nil { - utils.Logger.Err(fmt.Sprintf(" Storing costs for CDR %+v, costDetails: %+v, got error: %s", cdr, cdr.CostDetails, err.Error())) - } - } } // Attach CDR to stats - if self.stats != nil { // Send CDR to stats + if self.stats != nil && sendToStats { // Send CDR to stats var out int if err := self.stats.Call("CDRStatsV1.AppendCDR", cdr, &out); err != nil { utils.Logger.Err(fmt.Sprintf(" Could not append cdr to stats: %s", err.Error())) @@ -329,35 +293,31 @@ func (self *CdrServer) rateStoreStatsReplicate(cdr *StoredCdr) error { return nil } -func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { - if len(storedCdr.MediationRunId) == 0 { - storedCdr.MediationRunId = utils.META_DEFAULT - } - cdrRuns := []*StoredCdr{storedCdr} - if storedCdr.Rated { // Do not derive already rated CDRs since they should be already derived +func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { + cdrRuns := []*CDR{cdr} + if cdr.RunID != utils.MetaRaw { // Only derive *raw CDRs return cdrRuns, nil } - attrsDC := &utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction, - Account: storedCdr.Account, Subject: storedCdr.Subject, Destination: storedCdr.Destination} + attrsDC := &utils.AttrDerivedChargers{Tenant: cdr.Tenant, Category: cdr.Category, Direction: cdr.Direction, + Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination} var dcs utils.DerivedChargers if err := self.client.Call("Responder.GetDerivedChargers", attrsDC, &dcs); err != nil { - utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error())) + utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", cdr.CGRID, err.Error())) return nil, err } for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { - if fltrPass, _ := storedCdr.PassesFieldFilter(dcRunFilter); !fltrPass { + if fltrPass, _ := cdr.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched - continue } - dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField) + dcRequestTypeFld, _ := utils.NewRSRField(dc.RequestTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) @@ -365,17 +325,17 @@ func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) - dcPddFld, _ := utils.NewRSRField(dc.PddField) + 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) - forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, + forkedCdr, err := cdr.ForkCdr(dc.RunID, dcRequestTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, []*utils.RSRField{}, true, self.cgrCfg.DefaultTimezone) if err != nil { - utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", storedCdr.CgrId, dc.RunId, err.Error())) + 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 } if !forkedCdr.Rated { @@ -386,30 +346,61 @@ func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { return cdrRuns, nil } +func (self *CdrServer) rateCDR(cdr *CDR) error { + var qryCC *CallCost + var err error + if cdr.RequestType == utils.META_NONE { + return nil + } + if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, cdr.RequestType) && cdr.Usage != 0 { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards + // Should be previously calculated and stored in DB + delay := utils.Fib() + for i := 0; i < 4; i++ { + qryCC, err = self.cdrDb.GetCallCostLog(cdr.CGRID, cdr.RunID) + if err == nil { + break + } + time.Sleep(delay()) + } + if err != nil && (err == gorm.RecordNotFound || err == mgov2.ErrNotFound) { //calculate CDR as for pseudoprepaid + utils.Logger.Warning(fmt.Sprintf(" WARNING: Could not find CallCostLog for cgrid: %s, source: %s, runid: %s, will recalculate", cdr.CGRID, utils.SESSION_MANAGER_SOURCE, cdr.RunID)) + qryCC, err = self.getCostFromRater(cdr) + } + + } else { + qryCC, err = self.getCostFromRater(cdr) + } + if err != nil { + return err + } else if qryCC != nil { + cdr.Cost = qryCC.Cost + cdr.CostDetails = qryCC + } + return nil +} + // Retrive the cost from engine -func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) { +func (self *CdrServer) getCostFromRater(cdr *CDR) (*CallCost, error) { cc := new(CallCost) var err error - timeStart := storedCdr.AnswerTime + timeStart := cdr.AnswerTime if timeStart.IsZero() { // Fix for FreeSWITCH unanswered calls - timeStart = storedCdr.SetupTime + timeStart = cdr.SetupTime } cd := &CallDescriptor{ - TOR: storedCdr.TOR, - Direction: storedCdr.Direction, - Tenant: storedCdr.Tenant, - Category: storedCdr.Category, - Subject: storedCdr.Subject, - Account: storedCdr.Account, - Destination: storedCdr.Destination, + TOR: cdr.ToR, + Direction: cdr.Direction, + Tenant: cdr.Tenant, + Category: cdr.Category, + Subject: cdr.Subject, + Account: cdr.Account, + Destination: cdr.Destination, TimeStart: timeStart, - TimeEnd: timeStart.Add(storedCdr.Usage), - DurationIndex: storedCdr.Usage, + TimeEnd: timeStart.Add(cdr.Usage), + DurationIndex: cdr.Usage, } - if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, storedCdr.ReqType) { // Prepaid - Cost can be recalculated in case of missing records from SM - if err = self.client.Call("Responder.Debit", cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled - self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc) - } + if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, cdr.RequestType) { // Prepaid - Cost can be recalculated in case of missing records from SM + err = self.client.Call("Responder.Debit", cd, cc) } else { err = self.client.Call("Responder.GetCost", cd, cc) } @@ -419,41 +410,8 @@ func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) return cc, nil } -func (self *CdrServer) rateCDR(storedCdr *StoredCdr) error { - var qryCC *CallCost - var err error - if storedCdr.ReqType == utils.META_NONE { - return nil - } - if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, storedCdr.ReqType) && storedCdr.Usage != 0 { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards - // Should be previously calculated and stored in DB - delay := utils.Fib() - for i := 0; i < 4; i++ { - qryCC, err = self.cdrDb.GetCallCostLog(storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId) - if err == nil { - break - } - time.Sleep(delay()) - } - if err != nil && (err == gorm.RecordNotFound || err == mgov2.ErrNotFound) { //calculate CDR as for pseudoprepaid - utils.Logger.Warning(fmt.Sprintf(" WARNING: Could not find CallCostLog for cgrid: %s, source: %s, runid: %s, will recalculate", storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId)) - qryCC, err = self.getCostFromRater(storedCdr) - } - - } else { - qryCC, err = self.getCostFromRater(storedCdr) - } - if err != nil { - return err - } else if qryCC != nil { - storedCdr.Cost = qryCC.Cost - storedCdr.CostDetails = qryCC - } - return nil -} - // ToDo: Add websocket support -func (self *CdrServer) replicateCdr(cdr *StoredCdr) error { +func (self *CdrServer) replicateCdr(cdr *CDR) error { for _, rplCfg := range self.cgrCfg.CDRSCdrReplication { passesFilters := true for _, cdfFltr := range rplCfg.CdrFilter { @@ -475,7 +433,6 @@ func (self *CdrServer) replicateCdr(cdr *StoredCdr) error { content = utils.CONTENT_JSON body = cdr } - errChan := make(chan error) go func(body interface{}, rplCfg *config.CdrReplicationCfg, content string, errChan chan error) { fallbackPath := path.Join( diff --git a/engine/cdrstats.go b/engine/cdrstats.go index 6ff1dae4c..94d17cf51 100644 --- a/engine/cdrstats.go +++ b/engine/cdrstats.go @@ -64,7 +64,7 @@ type CdrStats struct { TOR []string // CDRFieldFilter on TORs CdrHost []string // CDRFieldFilter on CdrHosts CdrSource []string // CDRFieldFilter on CdrSources - ReqType []string // CDRFieldFilter on ReqTypes + ReqType []string // CDRFieldFilter on RequestTypes Direction []string // CDRFieldFilter on Directions Tenant []string // CDRFieldFilter on Tenants Category []string // CDRFieldFilter on Categories @@ -82,7 +82,7 @@ type CdrStats struct { Triggers ActionTriggers } -func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool { +func (cs *CdrStats) AcceptCdr(cdr *CDR) bool { if cdr == nil { return false } @@ -94,16 +94,16 @@ func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool { return false } } - if len(cs.TOR) > 0 && !utils.IsSliceMember(cs.TOR, cdr.TOR) { + if len(cs.TOR) > 0 && !utils.IsSliceMember(cs.TOR, cdr.ToR) { return false } - if len(cs.CdrHost) > 0 && !utils.IsSliceMember(cs.CdrHost, cdr.CdrHost) { + if len(cs.CdrHost) > 0 && !utils.IsSliceMember(cs.CdrHost, cdr.OriginHost) { return false } - if len(cs.CdrSource) > 0 && !utils.IsSliceMember(cs.CdrSource, cdr.CdrSource) { + if len(cs.CdrSource) > 0 && !utils.IsSliceMember(cs.CdrSource, cdr.Source) { return false } - if len(cs.ReqType) > 0 && !utils.IsSliceMember(cs.ReqType, cdr.ReqType) { + if len(cs.ReqType) > 0 && !utils.IsSliceMember(cs.ReqType, cdr.RequestType) { return false } if len(cs.Direction) > 0 && !utils.IsSliceMember(cs.Direction, cdr.Direction) { @@ -153,10 +153,10 @@ func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool { } } if len(cs.PddInterval) > 0 { - if cdr.Pdd < cs.PddInterval[0] { + if cdr.PDD < cs.PddInterval[0] { return false } - if len(cs.PddInterval) > 1 && cdr.Pdd >= cs.PddInterval[1] { + if len(cs.PddInterval) > 1 && cdr.PDD >= cs.PddInterval[1] { return false } } @@ -166,7 +166,7 @@ func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool { if len(cs.DisconnectCause) > 0 && !utils.IsSliceMember(cs.DisconnectCause, cdr.DisconnectCause) { return false } - if len(cs.MediationRunIds) > 0 && !utils.IsSliceMember(cs.MediationRunIds, cdr.MediationRunId) { + if len(cs.MediationRunIds) > 0 && !utils.IsSliceMember(cs.MediationRunIds, cdr.RunID) { return false } if len(cs.CostInterval) > 0 { @@ -177,12 +177,6 @@ func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool { return false } } - if len(cs.RatedAccount) > 0 && !utils.IsSliceMember(cs.RatedAccount, cdr.RatedAccount) { - return false - } - if len(cs.RatedSubject) > 0 && !utils.IsSliceMember(cs.RatedSubject, cdr.RatedSubject) { - return false - } return true } diff --git a/engine/cgrcdr.go b/engine/cgrcdr.go index db33e4020..7121070dc 100644 --- a/engine/cgrcdr.go +++ b/engine/cgrcdr.go @@ -31,7 +31,7 @@ func NewCgrCdrFromHttpReq(req *http.Request, timezone string) (CgrCdr, error) { } } cgrCdr := make(CgrCdr) - cgrCdr[utils.CDRHOST] = req.RemoteAddr + cgrCdr[utils.CDRSOURCE] = req.RemoteAddr for k, vals := range req.Form { cgrCdr[k] = vals[0] // We only support the first value for now, if more are provided it is considered remote's fault } @@ -40,9 +40,9 @@ func NewCgrCdrFromHttpReq(req *http.Request, timezone string) (CgrCdr, error) { type CgrCdr map[string]string -func (cgrCdr CgrCdr) getCgrId(timezone string) string { - if cgrId, hasIt := cgrCdr[utils.CGRID]; hasIt { - return cgrId +func (cgrCdr CgrCdr) getCGRID(timezone string) string { + if CGRID, hasIt := cgrCdr[utils.CGRID]; hasIt { + return CGRID } setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], timezone) return utils.Sha1(cgrCdr[utils.ACCID], setupTime.UTC().String()) @@ -58,22 +58,22 @@ func (cgrCdr CgrCdr) getExtraFields() map[string]string { return extraFields } -func (cgrCdr CgrCdr) AsStoredCdr(timezone string) *StoredCdr { - storCdr := new(StoredCdr) - storCdr.CgrId = cgrCdr.getCgrId(timezone) - storCdr.TOR = cgrCdr[utils.TOR] - storCdr.AccId = cgrCdr[utils.ACCID] - storCdr.CdrHost = cgrCdr[utils.CDRHOST] - storCdr.CdrSource = cgrCdr[utils.CDRSOURCE] - storCdr.ReqType = cgrCdr[utils.REQTYPE] - storCdr.Direction = "*out" +func (cgrCdr CgrCdr) AsStoredCdr(timezone string) *CDR { + storCdr := new(CDR) + storCdr.CGRID = cgrCdr.getCGRID(timezone) + storCdr.ToR = cgrCdr[utils.TOR] + storCdr.OriginID = cgrCdr[utils.ACCID] + 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.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] diff --git a/engine/cgrcdr_test.go b/engine/cgrcdr_test.go index 5aa544ca1..82648affe 100644 --- a/engine/cgrcdr_test.go +++ b/engine/cgrcdr_test.go @@ -26,45 +26,45 @@ import ( ) /* -curl --data "accid=asbfdsaf&cdrhost=192.168.1.1&reqtype=rated&direction=*out&tenant=cgrates.org&tor=call&account=1001&subject=1001&destination=1002&time_answer=1383813746&duration=10&field_extr1=val_extr1&fieldextr2=valextr2" http://ipbxdev:2080/cgr +curl --data "OriginID=asbfdsaf&OriginHost=192.168.1.1&RequestType=rated&direction=*out&tenant=cgrates.org&tor=call&account=1001&subject=1001&destination=1002&time_answer=1383813746&duration=10&field_extr1=val_extr1&fieldextr2=valextr2" http://ipbxdev:2080/cgr */ func TestCgrCdrInterfaces(t *testing.T) { var _ RawCdr = make(CgrCdr) } -func TestCgrCdrAsStoredCdr(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"} setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME], "") - expctRtCdr := &StoredCdr{CgrId: utils.Sha1(cgrCdr[utils.ACCID], setupTime.String()), TOR: utils.VOICE, AccId: cgrCdr[utils.ACCID], CdrHost: cgrCdr[utils.CDRHOST], - CdrSource: cgrCdr[utils.CDRSOURCE], - ReqType: cgrCdr[utils.REQTYPE], - Direction: cgrCdr[utils.DIRECTION], Tenant: cgrCdr[utils.TENANT], Category: cgrCdr[utils.CATEGORY], Account: cgrCdr[utils.ACCOUNT], Subject: cgrCdr[utils.SUBJECT], + 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} - if storedCdr := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, storedCdr) { - t.Errorf("Expecting %v, received: %v", expctRtCdr, storedCdr) + if CDR := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, CDR) { + t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR) } } -// Make sure the replicated CDR matches the expected StoredCdr -func TestReplicatedCgrCdrAsStoredCdr(t *testing.T) { +// Make sure the replicated CDR matches the expected CDR +func TestReplicatedCgrCdrAsCDR(t *testing.T) { cgrCdr := CgrCdr{utils.CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", 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.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 := &StoredCdr{CgrId: cgrCdr[utils.CGRID], - TOR: cgrCdr[utils.TOR], - AccId: cgrCdr[utils.ACCID], - CdrHost: cgrCdr[utils.CDRHOST], - CdrSource: cgrCdr[utils.CDRSOURCE], - ReqType: cgrCdr[utils.REQTYPE], + 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], @@ -72,7 +72,7 @@ func TestReplicatedCgrCdrAsStoredCdr(t *testing.T) { 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, + 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], @@ -81,7 +81,7 @@ func TestReplicatedCgrCdrAsStoredCdr(t *testing.T) { Cost: 0.12, Rated: true, } - if storedCdr := cgrCdr.AsStoredCdr(""); !reflect.DeepEqual(expctRtCdr, storedCdr) { - t.Errorf("Expecting %v, received: %v", expctRtCdr, storedCdr) + 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 e6a9627f7..91803856f 100644 --- a/engine/event.go +++ b/engine/event.go @@ -33,6 +33,7 @@ type Event interface { GetAccount(string) string GetDestination(string) string GetCallDestNr(string) string + GetOriginatorIP(string) string GetCategory(string) string GetTenant(string) string GetReqType(string) string @@ -43,12 +44,11 @@ type Event interface { GetPdd(string) (time.Duration, error) GetSupplier(string) string GetDisconnectCause(string) string - GetOriginatorIP(string) string GetExtraFields() map[string]string MissingParameter(string) bool ParseEventValue(*utils.RSRField, string) string PassesFieldFilter(*utils.RSRField) (bool, string) - AsStoredCdr(timezone string) *StoredCdr + AsStoredCdr(timezone string) *CDR String() string AsEvent(string) Event ComputeLcr() bool diff --git a/engine/fscdr.go b/engine/fscdr.go index b4fb36306..8ab7ad753 100644 --- a/engine/fscdr.go +++ b/engine/fscdr.go @@ -70,7 +70,7 @@ type FSCdr struct { body map[string]interface{} // keeps the loaded body for extra field search } -func (fsCdr FSCdr) getCgrId(timezone string) string { +func (fsCdr FSCdr) getCGRID(timezone string) string { setupTime, _ := utils.ParseTimeDetectLayout(fsCdr.vars[FS_SETUP_TIME], timezone) return utils.Sha1(fsCdr.vars[FS_UUID], setupTime.UTC().String()) } @@ -118,14 +118,14 @@ func (fsCdr FSCdr) searchExtraField(field string, body map[string]interface{}) ( return } -func (fsCdr FSCdr) AsStoredCdr(timezone string) *StoredCdr { - storCdr := new(StoredCdr) - storCdr.CgrId = fsCdr.getCgrId(timezone) - storCdr.TOR = utils.VOICE - storCdr.AccId = fsCdr.vars[FS_UUID] - storCdr.CdrHost = fsCdr.vars[FS_IP] - storCdr.CdrSource = FS_CDR_SOURCE - storCdr.ReqType = utils.FirstNonEmpty(fsCdr.vars[utils.CGR_REQTYPE], fsCdr.cgrCfg.DefaultReqType) +func (fsCdr FSCdr) AsStoredCdr(timezone string) *CDR { + storCdr := new(CDR) + storCdr.CGRID = fsCdr.getCGRID(timezone) + storCdr.ToR = utils.VOICE + storCdr.OriginID = fsCdr.vars[FS_UUID] + 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) @@ -134,8 +134,8 @@ func (fsCdr FSCdr) AsStoredCdr(timezone string) *StoredCdr { 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 = pddStr + "ms" - storCdr.Pdd, _ = time.ParseDuration(pddStr) + 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] diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go index 521d7b5f0..bdd7ffa50 100644 --- a/engine/fscdr_test.go +++ b/engine/fscdr_test.go @@ -55,12 +55,12 @@ func TestCDRFields(t *testing.T) { } setupTime, _ := utils.ParseTimeDetectLayout("1436280728", "") answerTime, _ := utils.ParseTimeDetectLayout("1436280728", "") - expctStoredCdr := &StoredCdr{CgrId: "164b0422fdc6a5117031b427439482c6a4f90e41", TOR: utils.VOICE, AccId: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", - CdrHost: "127.0.0.1", CdrSource: "freeswitch_json", Direction: utils.OUT, Category: "call", ReqType: 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", + 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} - if storedCdr := fsCdr.AsStoredCdr(""); !reflect.DeepEqual(expctStoredCdr, storedCdr) { - t.Errorf("Expecting: %v, received: %v", expctStoredCdr, storedCdr) + if CDR := fsCdr.AsStoredCdr(""); !reflect.DeepEqual(expctCDR, CDR) { + t.Errorf("Expecting: %v, received: %v", expctCDR, CDR) } } diff --git a/engine/handler_derivedcharging.go b/engine/handler_derivedcharging.go index d5dc087f8..52f48eb03 100644 --- a/engine/handler_derivedcharging.go +++ b/engine/handler_derivedcharging.go @@ -43,14 +43,14 @@ func HandleGetDerivedChargers(ratingStorage RatingStorage, attrs *utils.AttrDeri } func DerivedChargersMatchesDest(dcs *utils.DerivedChargers, dest string) bool { - if len(dcs.DestinationIds) == 0 || dcs.DestinationIds[utils.ANY] { + if len(dcs.DestinationIDs) == 0 || dcs.DestinationIDs[utils.ANY] { return true } // check destination ids for _, p := range utils.SplitPrefix(dest, MIN_PREFIX_MATCH) { if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil { destIds := x.(map[interface{}]struct{}) - for value := range dcs.DestinationIds { + for value := range dcs.DestinationIDs { for idId := range destIds { dId := idId.(string) if value == dId { diff --git a/engine/handler_derivedcharging_test.go b/engine/handler_derivedcharging_test.go index 83a4d2e54..8a2c98f54 100644 --- a/engine/handler_derivedcharging_test.go +++ b/engine/handler_derivedcharging_test.go @@ -95,7 +95,7 @@ func TestHandleGetStoredDC(t *testing.T) { func TestHandleDeivedChargersMatchDestRet(t *testing.T) { dcs := &utils.DerivedChargers{ - DestinationIds: utils.NewStringMap("RET"), + DestinationIDs: utils.NewStringMap("RET"), } if !DerivedChargersMatchesDest(dcs, "0723045326") { t.Error("Derived charger failed to match dest") @@ -104,7 +104,7 @@ func TestHandleDeivedChargersMatchDestRet(t *testing.T) { func TestHandleDeivedChargersMatchDestNat(t *testing.T) { dcs := &utils.DerivedChargers{ - DestinationIds: utils.NewStringMap("NAT"), + DestinationIDs: utils.NewStringMap("NAT"), } if !DerivedChargersMatchesDest(dcs, "0723045326") { t.Error("Derived charger failed to match dest") @@ -113,7 +113,7 @@ func TestHandleDeivedChargersMatchDestNat(t *testing.T) { func TestHandleDeivedChargersMatchDestNatRet(t *testing.T) { dcs := &utils.DerivedChargers{ - DestinationIds: utils.NewStringMap("NAT", "RET"), + DestinationIDs: utils.NewStringMap("NAT", "RET"), } if !DerivedChargersMatchesDest(dcs, "0723045326") { t.Error("Derived charger failed to match dest") diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index ab922c9e0..fc8d985dc 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -210,7 +210,7 @@ cgrates.org,alodis,TOPUP_EMPTY_AT,,true,true ` derivedCharges = ` -#Direction,Tenant,Category,Account,Subject,DestinationIds,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,PddField,AnswerTimeField,UsageField,SupplierField,DisconnectCauseField,CostField,RatedField +#Direction,Tenant,Category,Account,Subject,DestinationIds,RunId,RunFilter,RequestTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,PddField,AnswerTimeField,UsageField,SupplierField,DisconnectCauseField,CostField,RatedField *out,cgrates.org,call,dan,dan,,extra1,^filteredHeader1/filterValue1/,^prepaid,,,,rif,rif,,,,,,,,, *out,cgrates.org,call,dan,dan,,extra2,,,,,,ivo,ivo,,,,,,,,, *out,cgrates.org,call,dan,*any,,extra1,,,,,,rif2,rif2,,,,,,,,, @@ -1122,15 +1122,15 @@ func TestLoadDerivedChargers(t *testing.T) { t.Error("Failed to load derivedChargers: ", csvr.derivedChargers) } expCharger1 := &utils.DerivedChargers{ - DestinationIds: utils.StringMap{}, + DestinationIDs: utils.StringMap{}, Chargers: []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", RunFilters: "^filteredHeader1/filterValue1/", ReqTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, + &utils.DerivedCharger{RunID: "extra1", RunFilters: "^filteredHeader1/filterValue1/", RequestTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: utils.META_DEFAULT, - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "ivo", SubjectField: "ivo", DestinationField: utils.META_DEFAULT, - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, }} keyCharger1 := utils.DerivedChargersKey("*out", "cgrates.org", "call", "dan", "dan") diff --git a/engine/models.go b/engine/models.go index 99d8c505b..ead7492dc 100644 --- a/engine/models.go +++ b/engine/models.go @@ -1,14 +1,14 @@ /* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2012-2015 ITsysCOM +Real-time Charging System for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH -This program is free software: you can redistribute it and/or modify +This program is free software: you can Storagetribute 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 +but WITH*out ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -392,74 +392,15 @@ func (ta *TpAlias) GetId() string { return utils.ConcatenatedKey(ta.Direction, ta.Tenant, ta.Category, ta.Account, ta.Subject, ta.Context) } -type TblCdrsPrimary struct { - Id int64 +type TBLCDRs struct { + ID int64 Cgrid string + RunID string + OriginHost string + Source string + OriginID string Tor string - Accid string - Cdrhost string - Cdrsource string - Reqtype 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 - CreatedAt time.Time - DeletedAt time.Time -} - -func (t TblCdrsPrimary) TableName() string { - return utils.TBL_CDRS_PRIMARY -} - -type TblCdrsExtra struct { - Id int64 - Cgrid string - ExtraFields string - CreatedAt time.Time - DeletedAt time.Time -} - -func (t TblCdrsExtra) TableName() string { - return utils.TBL_CDRS_EXTRA -} - -type TblCostDetail struct { - Id int64 - Cgrid string - Runid string - Tor string - Direction string - Tenant string - Category string - Account string - Subject string - Destination string - Cost float64 - Timespans string - CostSource string - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt time.Time -} - -func (t TblCostDetail) TableName() string { - return utils.TBL_COST_DETAILS -} - -type TblRatedCdr struct { - Id int64 - Cgrid string - Runid string - Reqtype string + RequestType string Direction string Tenant string Category string @@ -472,13 +413,30 @@ type TblRatedCdr struct { Usage float64 Supplier string DisconnectCause string + ExtraFields string Cost float64 + CostDetails string + CostSource string ExtraInfo string CreatedAt time.Time UpdatedAt time.Time DeletedAt time.Time } -func (t TblRatedCdr) TableName() string { - return utils.TBL_RATED_CDRS +func (t TBLCDRs) TableName() string { + return utils.TBL_CDRS +} + +type TBLSMCosts struct { + ID int64 + Cgrid string + RunID string + CostSource string + CostDetails string + CreatedAt time.Time + DeletedAt time.Time +} + +func (t TBLSMCosts) TableName() string { + return utils.TBLSMCosts } diff --git a/engine/rawcdr.go b/engine/rawcdr.go index 472ecd175..f186c8bc2 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) *StoredCdr // Convert the inbound Cdr into internally used one, CgrCdr + AsStoredCdr(string) *CDR // Convert the inbound Cdr into internally used one, CgrCdr } diff --git a/engine/responder.go b/engine/responder.go index 7843c609a..00a605356 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -260,8 +260,8 @@ func (rs *Responder) GetMaxSessionTime(arg *CallDescriptor, reply *float64) (err } // Returns MaxSessionTime for an event received in SessionManager, considering DerivedCharging for it -func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) error { - cacheKey := "GetDerivedMaxSessionTime" + ev.CgrId +func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { + cacheKey := "GetDerivedMaxSessionTime" + ev.CGRID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { *reply = item.Value.(float64) return item.Err @@ -303,7 +303,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err } dcs, _ = dcs.AppendDefaultRun() for _, dc := range dcs.Chargers { - if utils.IsSliceMember([]string{utils.META_RATED, utils.RATED}, ev.GetReqType(dc.ReqTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime + if utils.IsSliceMember([]string{utils.META_RATED, utils.RATED}, ev.GetReqType(dc.RequestTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime continue } runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) @@ -347,7 +347,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err rs.getCache().Cache(cacheKey, &cache2go.CacheItem{Err: err}) return err } - if utils.IsSliceMember([]string{utils.META_POSTPAID, utils.POSTPAID}, ev.GetReqType(dc.ReqTypeField)) { + if utils.IsSliceMember([]string{utils.META_POSTPAID, utils.POSTPAID}, ev.GetReqType(dc.RequestTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime, do it here for unauthorized destination error check continue } @@ -364,8 +364,8 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err } // Used by SM to get all the prepaid CallDescriptors attached to a session -func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { - cacheKey := "GetSessionRuns" + ev.CgrId +func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error { + cacheKey := "GetSessionRuns" + ev.CGRID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { *sRuns = item.Value.([]*SessionRun) return item.Err @@ -407,7 +407,7 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { dcs, _ = dcs.AppendDefaultRun() sesRuns := make([]*SessionRun, 0) for _, dc := range dcs.Chargers { - if !utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, ev.GetReqType(dc.ReqTypeField)) { + if !utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, ev.GetReqType(dc.RequestTypeField)) { continue // We only consider prepaid sessions } startTime, err := ev.GetAnswerTime(dc.AnswerTimeField, rs.Timezone) @@ -613,7 +613,6 @@ func (rs *Responder) Call(serviceMethod string, args interface{}, reply interfac if !method.IsValid() { return utils.ErrNotImplemented } - // construct the params params := []reflect.Value{reflect.ValueOf(args), reflect.ValueOf(reply)} diff --git a/engine/responder_test.go b/engine/responder_test.go index 1e7a23889..94235c95a 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -35,8 +35,8 @@ func init() { // Test internal abilites of GetDerivedChargers func TestResponderGetDerivedChargers(t *testing.T) { - - cfgedDC := &utils.DerivedChargers{DestinationIds: utils.StringMap{}, Chargers: []*utils.DerivedCharger{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: utils.META_DEFAULT, DirectionField: "test", TenantField: "test", + 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"} @@ -56,11 +56,11 @@ func TestResponderGetDerivedChargers(t *testing.T) { func TestResponderGetDerivedMaxSessionTime(t *testing.T) { testTenant := "vdf" - cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan", Subject: "dan", + 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), - MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"} + 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) @@ -83,11 +83,11 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { } keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan", "dan") charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^" + utils.META_PREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^" + utils.META_PREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^dan", SubjectField: "^dan", DestinationField: "^+49151708707", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^ivo", SubjectField: "^ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra3", RequestTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^rif", SubjectField: "^rif", DestinationField: "^+49151708707", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, }} if err := ratingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { @@ -122,25 +122,26 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { func TestResponderGetSessionRuns(t *testing.T) { testTenant := "vdf" - cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", - CdrHost: "192.168.1.1", CdrSource: "test", ReqType: 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", - MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"} + cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf", + OriginHost: "192.168.1.1", Source: "test", RequestType: utils.META_PREPAID, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2", + Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), PDD: 3 * time.Second, + AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Supplier: "suppl1", + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, + ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01} keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan2", "dan2") - dfDC := &utils.DerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + dfDC := &utils.DerivedCharger{RunID: utils.DEFAULT_RUNID, RequestTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: utils.META_DEFAULT, SubjectField: utils.META_DEFAULT, DestinationField: utils.META_DEFAULT, - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT} - extra1DC := &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^" + utils.META_PREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + extra1DC := &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^" + utils.META_PREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: "^0", AccountField: "^minitsboy", SubjectField: "^rif", DestinationField: "^0256", - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} - extra2DC := &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} + extra2DC := &utils.DerivedCharger{RunID: "extra2", RequestTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "^ivo", SubjectField: "^ivo", DestinationField: utils.META_DEFAULT, SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} - extra3DC := &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + extra3DC := &utils.DerivedCharger{RunID: "extra3", RequestTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, CategoryField: "^0", AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PDDField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT} charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{extra1DC, extra2DC, extra3DC}} if err := ratingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { @@ -489,9 +490,10 @@ func TestResponderGetLCR(t *testing.T) { } else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) { t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts) } - cdr := &StoredCdr{Supplier: "rif12", AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} + + cdr := &CDR{Supplier: "rif12", AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1} rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) - cdr = &StoredCdr{Supplier: "dan12", AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} + cdr = &CDR{Supplier: "dan12", AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2} rsponder.Stats.Call("CDRStatsV1.AppendCDR", cdr, &r) eQTLcr = &LCRCost{ diff --git a/engine/stats.go b/engine/stats.go index 62ff95c48..e130a4e25 100644 --- a/engine/stats.go +++ b/engine/stats.go @@ -257,7 +257,7 @@ func (s *Stats) setupQueueSaver(sq *StatsQueue) { } } -func (s *Stats) AppendCDR(cdr *StoredCdr, out *int) error { +func (s *Stats) AppendCDR(cdr *CDR, out *int) error { s.mux.RLock() defer s.mux.RUnlock() for _, sq := range s.queues { diff --git a/engine/stats_queue.go b/engine/stats_queue.go index c9bd1619f..bfc07356d 100644 --- a/engine/stats_queue.go +++ b/engine/stats_queue.go @@ -111,7 +111,7 @@ func (sq *StatsQueue) Load(saved *StatsQueue) { } } -func (sq *StatsQueue) AppendCDR(cdr *StoredCdr) { +func (sq *StatsQueue) AppendCDR(cdr *CDR) { sq.mux.Lock() defer sq.mux.Unlock() if sq.conf.AcceptCdr(cdr) { @@ -162,11 +162,11 @@ func (sq *StatsQueue) removeFromMetrics(cdr *QCdr) { } } -func (sq *StatsQueue) simplifyCdr(cdr *StoredCdr) *QCdr { +func (sq *StatsQueue) simplifyCdr(cdr *CDR) *QCdr { return &QCdr{ SetupTime: cdr.SetupTime, AnswerTime: cdr.AnswerTime, - Pdd: cdr.Pdd, + Pdd: cdr.PDD, Usage: cdr.Usage, Cost: cdr.Cost, Dest: cdr.Destination, diff --git a/engine/stats_test.go b/engine/stats_test.go index 2823fad38..def739f13 100644 --- a/engine/stats_test.go +++ b/engine/stats_test.go @@ -34,7 +34,7 @@ func TestStatsQueueInit(t *testing.T) { func TestStatsValue(t *testing.T) { sq := NewStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, TCD, ACC, TCC}}) - cdr := &StoredCdr{ + cdr := &CDR{ AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), Usage: 10 * time.Second, Cost: 1, @@ -55,22 +55,22 @@ func TestStatsValue(t *testing.T) { } func TestStatsSimplifyCDR(t *testing.T) { - cdr := &StoredCdr{ - TOR: "tor", - AccId: "accid", - CdrHost: "cdrhost", - CdrSource: "cdrsource", - ReqType: "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, - MediationRunId: "mri", - Cost: 10, + 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 := &StatsQueue{} qcdr := sq.simplifyCdr(cdr) @@ -84,12 +84,12 @@ func TestStatsSimplifyCDR(t *testing.T) { func TestAcceptCdr(t *testing.T) { sq := NewStatsQueue(nil) - cdr := &StoredCdr{ - TOR: "tor", - AccId: "accid", - CdrHost: "cdrhost", - CdrSource: "cdrsource", - ReqType: "reqtype", + cdr := &CDR{ + ToR: "tor", + OriginID: "accid", + OriginHost: "cdrhost", + Source: "cdrsource", + RequestType: "reqtype", Direction: "direction", Tenant: "tenant", Category: "category", @@ -98,10 +98,10 @@ func TestAcceptCdr(t *testing.T) { Destination: "0723045326", SetupTime: time.Date(2014, 7, 3, 13, 43, 0, 0, time.UTC), Usage: 10 * time.Second, - Pdd: 7 * time.Second, + PDD: 7 * time.Second, Supplier: "supplier1", DisconnectCause: "normal", - MediationRunId: "mri", + RunID: "mri", Cost: 10, } sq.conf = &CdrStats{} @@ -148,14 +148,6 @@ func TestAcceptCdr(t *testing.T) { if sq.conf.AcceptCdr(cdr) == true { t.Errorf("Should have NOT accepted this CDR: %+v", cdr) } - sq.conf = &CdrStats{RatedAccount: []string{"test"}} - if sq.conf.AcceptCdr(cdr) == true { - t.Errorf("Should have NOT accepted this CDR: %+v", cdr) - } - sq.conf = &CdrStats{RatedSubject: []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) @@ -217,7 +209,7 @@ func TestStatsQueueIds(t *testing.T) { func TestStatsAppendCdr(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -241,7 +233,7 @@ func TestStatsAppendCdr(t *testing.T) { func TestStatsGetValues(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -250,7 +242,7 @@ func TestStatsGetValues(t *testing.T) { Cost: 10, } cdrStats.AppendCDR(cdr, nil) - cdr = &StoredCdr{ + cdr = &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -270,7 +262,7 @@ func TestStatsGetValues(t *testing.T) { func TestStatsReloadQueues(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -305,7 +297,7 @@ func TestStatsReloadQueuesWithDefault(t *testing.T) { cdrStats.AddQueue(&CdrStats{ Id: utils.META_DEFAULT, }, nil) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -338,7 +330,7 @@ func TestStatsReloadQueuesWithDefault(t *testing.T) { func TestStatsReloadQueuesWithIds(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -370,7 +362,7 @@ func TestStatsReloadQueuesWithIds(t *testing.T) { func TestStatsSaveQueues(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -388,7 +380,7 @@ func TestStatsSaveQueues(t *testing.T) { func TestStatsResetQueues(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), @@ -420,7 +412,7 @@ func TestStatsResetQueues(t *testing.T) { func TestStatsResetQueuesWithIds(t *testing.T) { cdrStats := NewStats(ratingStorage, accountingStorage, 0) - cdr := &StoredCdr{ + cdr := &CDR{ Tenant: "cgrates.org", Category: "call", AnswerTime: time.Now(), diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go new file mode 100644 index 000000000..5f886aa4e --- /dev/null +++ b/engine/storage_cdrs_it_test.go @@ -0,0 +1,780 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2012-2015 ITsysCOM + +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 ( + "flag" + "fmt" + "path" + //"reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +var testIntegration = flag.Bool("integration", false, "Perform the tests in integration mode, not by default.") // This flag will be passed here via "go test -local" args + +func TestITCDRsMySQL(t *testing.T) { + if !*testIntegration { + return + } + cfg, err := config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "mysql")) + if err != nil { + t.Error(err) + } + if err := testGetCDRs(cfg); err != nil { + t.Error(err) + } + if err := testSetCDR(cfg); err != nil { + t.Error(err) + } + if err := testSMCosts(cfg); err != nil { + t.Error(err) + } +} + +func TestITCDRsPSQL(t *testing.T) { + if !*testIntegration { + return + } + cfg, err := config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "postgres")) + if err != nil { + t.Error(err) + } + if err := testGetCDRs(cfg); err != nil { + t.Error(err) + } + if err := testSetCDR(cfg); err != nil { + t.Error(err) + } + if err := testSMCosts(cfg); err != nil { + t.Error(err) + } +} + +func TestITCDRsMongo(t *testing.T) { + if !*testIntegration { + return + } + cfg, err := config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "mongo")) + if err != nil { + t.Error(err) + } + if err := testGetCDRs(cfg); err != nil { + t.Error(err) + } + if err := testSetCDR(cfg); err != nil { + t.Error(err) + } + if err := testSMCosts(cfg); err != nil { + t.Error(err) + } +} + +// helper function to populate CDRs and check if they were stored in storDb +func testSetCDR(cfg *config.CGRConfig) error { + if err := InitStorDb(cfg); err != nil { + return err + } + cdrStorage, err := ConfigureCdrStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, + cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns) + if err != nil { + 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, + } + if err := cdrStorage.SetCDR(rawCDR, false); err != nil { + return fmt.Errorf("rawCDR: %+v, SetCDR err: %s", rawCDR, err.Error()) + } + if cdrs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{rawCDR.CGRID}, RunIDs: []string{utils.MetaRaw}}); err != nil { + return fmt.Errorf("rawCDR: %+v, GetCDRs err: %s", rawCDR, err.Error()) + } else if len(cdrs) != 1 { + 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, + } + if err := cdrStorage.SetCDR(ratedCDR, false); err != nil { + return fmt.Errorf("ratedCDR: %+v, SetCDR err: %s", ratedCDR, err.Error()) + } + if cdrs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ratedCDR.CGRID}, RunIDs: []string{ratedCDR.RunID}}); err != nil { + return fmt.Errorf("ratedCDR: %+v, GetCDRs err: %s", ratedCDR, err.Error()) + } else if len(cdrs) != 1 { + return fmt.Errorf("ratedCDR %+v, Unexpected number of CDRs returned: %d", ratedCDR, len(cdrs)) + } else { + if cdrs[0].RunID != ratedCDR.RunID { + return fmt.Errorf("Unexpected ratedCDR received: %+v", cdrs[0]) + } + if cdrs[0].RequestType != ratedCDR.RequestType { + return fmt.Errorf("Unexpected ratedCDR received: %+v", cdrs[0]) + } + if cdrs[0].Cost != ratedCDR.Cost { + return fmt.Errorf("Unexpected ratedCDR received: %+v", cdrs[0]) + } + } + // Make sure duplicating does not work + if err := cdrStorage.SetCDR(ratedCDR, false); err == nil { + return fmt.Errorf("Duplicating ratedCDR: %+v works", ratedCDR) + } + ratedCDR.RequestType = utils.META_RATED + ratedCDR.Cost = 0.34 + if err := cdrStorage.SetCDR(ratedCDR, true); err != nil { + return fmt.Errorf("Rerating ratedCDR: %+v, SetCDR err: %s", ratedCDR, err.Error()) + } + if cdrs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ratedCDR.CGRID}, RunIDs: []string{ratedCDR.RunID}}); err != nil { + return fmt.Errorf("Rerating ratedCDR: %+v, GetCDRs err: %s", ratedCDR, err.Error()) + } else if len(cdrs) != 1 { + return fmt.Errorf("Rerating ratedCDR %+v, Unexpected number of CDRs returned: %d", ratedCDR, len(cdrs)) + } else { + if cdrs[0].RunID != ratedCDR.RunID { + return fmt.Errorf("Unexpected ratedCDR received after rerating: %+v", cdrs[0]) + } + if cdrs[0].RequestType != ratedCDR.RequestType { + return fmt.Errorf("Unexpected ratedCDR received after rerating: %+v", cdrs[0]) + } + if cdrs[0].Cost != ratedCDR.Cost { + return fmt.Errorf("Unexpected ratedCDR received after rerating: %+v", cdrs[0]) + } + } + return nil +} + +func testSMCosts(cfg *config.CGRConfig) error { + if err := InitStorDb(cfg); err != nil { + return err + } + cdrStorage, err := ConfigureCdrStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, + cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns) + if err != nil { + return err + } + cc := &CallCost{ + Direction: utils.OUT, + Destination: "+4986517174963", + Timespans: []*TimeSpan{ + &TimeSpan{ + TimeStart: time.Date(2015, 12, 28, 8, 53, 0, 0, time.UTC).Local(), // MongoDB saves timestamps in local timezone + TimeEnd: time.Date(2015, 12, 28, 8, 54, 40, 0, time.UTC).Local(), + DurationIndex: 0, + RateInterval: &RateInterval{Rating: &RIRate{Rates: RateGroups{&Rate{GroupIntervalStart: 0, Value: 100, RateIncrement: 10 * time.Second, RateUnit: time.Second}}}}, + }, + }, + TOR: utils.VOICE, + } + if err := cdrStorage.LogCallCost("164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT, utils.UNIT_TEST, cc); err != nil { + return err + } + if rcvCC, err := cdrStorage.GetCallCostLog("164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT); err != nil { + return err + } else if len(cc.Timespans) != len(rcvCC.Timespans) { // cc.Timespans[0].RateInterval.Rating.Rates[0], rcvCC.Timespans[0].RateInterval.Rating.Rates[0]) + return fmt.Errorf("Expecting: %+v, received: %+v", cc, rcvCC) + } + return nil +} + +func testGetCDRs(cfg *config.CGRConfig) error { + if err := InitStorDb(cfg); err != nil { + return err + } + cdrStorage, err := ConfigureCdrStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, + cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns) + if err != nil { + return err + } + // All CDRs, no filter + if CDRs, _, err := cdrStorage.GetCDRs(new(utils.CDRsFilter)); err != nil { + return err + } else if len(CDRs) != 0 { + return fmt.Errorf("Unexpected number of CDRs returned: ", CDRs) + } + 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, + }, + &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, + }, + &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, + }, + &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, + }, + &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, + }, + &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", + }, + &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, + }, + &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, + }, + &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{"Hdr4": "HdrVal4"}, + 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{"Hdr4": "HdrVal4"}, + CostSource: "rater", + Cost: 0.15, + }, + } + // Store all CDRs + for _, cdr := range cdrs { + if err := cdrStorage.SetCDR(cdr, false); err != nil { + return fmt.Errorf("CDR: %+v, SetCDR err: %s", cdr, err.Error()) + } + } + // All CDRs, no filter + if CDRs, _, err := cdrStorage.GetCDRs(new(utils.CDRsFilter)); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("GetCDRs, unexpected number of CDRs returned: %d", len(CDRs)) + } + // Count ALL + if CDRs, count, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Count: true}); err != nil { + return err + } else if len(CDRs) != 0 { + return fmt.Errorf("CountCDRs, unexpected number of CDRs returned: %+v", CDRs) + } else if count != 10 { + return fmt.Errorf("CountCDRs, unexpected count of CDRs returned: %+v", count) + } + // Limit 5 + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Limit 5, unexpected number of CDRs returned: %+v", CDRs) + } + // Offset 5 + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Offset 5, unexpected number of CDRs returned: %+v", CDRs) + } + // Offset with limit 2 + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(2), Offset: utils.IntPointer(5)}}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Offset with limit 2, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on cgrids + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ + utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + }}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on CGRIDs, unexpected number of CDRs returned: %+v", CDRs) + } + // Count on CGRIDS + if _, count, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ + utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + }, Count: true}); err != nil { + return err + } else if count != 5 { + return fmt.Errorf("Count on CGRIDs, unexpected count of CDRs returned: %d", count) + } + // Filter on cgrids plus reqType + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ + utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + }, RequestTypes: []string{utils.META_PREPAID}}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Filter on cgrids plus reqType, unexpected number of CDRs returned: %+v", CDRs) + } + // Count on multiple filter + if _, count, err := cdrStorage.GetCDRs(&utils.CDRsFilter{CGRIDs: []string{ + utils.Sha1("testevent1", time.Date(2015, 12, 12, 14, 52, 0, 0, time.UTC).String()), + utils.Sha1("testevent3", time.Date(2015, 12, 28, 12, 58, 0, 0, time.UTC).String()), + }, RequestTypes: []string{utils.META_PREPAID}, Count: true}); err != nil { + return err + } else if count != 2 { + return fmt.Errorf("Count on multiple filter, unexpected count of CDRs returned: %d", count) + } + // Filter on RunID + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{RunIDs: []string{utils.DEFAULT_RUNID}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on RunID, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on TOR + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{ToRs: []string{utils.SMS}}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Filter on TOR, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple TOR + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{ToRs: []string{utils.SMS, utils.VOICE}}); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("Filter on multiple TOR, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on OriginHost + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{OriginHosts: []string{"127.0.0.1"}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on OriginHost, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple OriginHost + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{OriginHosts: []string{"127.0.0.1", "192.168.1.12"}}); err != nil { + return err + } else if len(CDRs) != 6 { + return fmt.Errorf("Filter on OriginHosts, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on Source + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Sources: []string{"testGetCDRs"}}); err != nil { + return err + } else if len(CDRs) != 6 { + return fmt.Errorf("Filter on Source, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple Sources + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Sources: []string{"testGetCDRs", "testGetCDRs5"}}); err != nil { + return err + } else if len(CDRs) != 8 { + return fmt.Errorf("Filter on Sources, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on reqType + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{RequestTypes: []string{utils.META_PREPAID}}); err != nil { + return err + } else if len(CDRs) != 4 { + return fmt.Errorf("Filter on RequestType, unexpected number of CDRs returned: %+v", len(CDRs)) + } + // Filter on multiple reqType + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{RequestTypes: []string{utils.META_PREPAID, utils.META_PSEUDOPREPAID}}); err != nil { + return err + } else if len(CDRs) != 6 { + return fmt.Errorf("Filter on RequestTypes, unexpected number of CDRs returned: %+v", CDRs) + } + + // Filter on direction + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Directions: []string{utils.OUT}}); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("Filter on Direction, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on Tenant + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Tenants: []string{"itsyscom.com"}}); err != nil { + return err + } else if len(CDRs) != 3 { + return fmt.Errorf("Filter on Tenant, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple tenants + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Tenants: []string{"itsyscom.com", "cgrates.org"}}); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("Filter on Tenants, Unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on Category + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Categories: []string{"call"}}); err != nil { + return err + } else if len(CDRs) != 7 { + return fmt.Errorf("Filter on Category, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple categories + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Categories: []string{"sms", "call_derived"}}); err != nil { + return err + } else if len(CDRs) != 3 { + return fmt.Errorf("Filter on Categories, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on account + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Accounts: []string{"1002"}}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Filter on Account, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple account + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Accounts: []string{"1001", "1002"}}); err != nil { + return err + } else if len(CDRs) != 7 { + return fmt.Errorf("Filter on Accounts, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on subject + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Subjects: []string{"1004"}}); err != nil { + return err + } else if len(CDRs) != 1 { + return fmt.Errorf("Filter on Subject, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple subject + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{Subjects: []string{"1002", "1003"}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on Subjects, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on destPrefix + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{DestinationPrefixes: []string{"10"}}); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("Filter on DestinationPrefix, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on multiple destPrefixes + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{DestinationPrefixes: []string{"1002", "1003"}}); err != nil { + return err + } else if len(CDRs) != 7 { + return fmt.Errorf("Filter on DestinationPrefix, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on not destPrefix + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{NotDestinationPrefixes: []string{"10"}}); err != nil { + return err + } else if len(CDRs) != 0 { + return fmt.Errorf("Filter on NotDestinationPrefix, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on not destPrefixes + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{NotDestinationPrefixes: []string{"1001", "1002"}}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on NotDestinationPrefix, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on hasPrefix and not HasPrefix + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{DestinationPrefixes: []string{"1002", "1003"}, + NotDestinationPrefixes: []string{"1002"}}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Filter on DestinationPrefix and NotDestinationPrefix, unexpected number of CDRs returned: %+v", CDRs) + } + + // Filter on MaxCost + var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil { + return err + } else if len(CDRs) != 5 { + return fmt.Errorf("Filter on MaxCost, unexpected number of CDRs returned: ", CDRs) + } else { + for i, cdr := range CDRs { + if i == 0 { + orderIdStart = cdr.OrderID + } + if cdr.OrderID < orderIdStart { + orderIdStart = cdr.OrderID + } + if cdr.OrderID > orderIdEnd { + orderIdEnd = cdr.OrderID + } + } + } + // Filter on orderIdStart + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{OrderIDStart: &orderIdStart}); err != nil { + return err + } else if len(CDRs) != 10 { + return fmt.Errorf("Filter on OrderIDStart, unexpected number of CDRs returned: %d", len(CDRs)) + } + // Filter on orderIdStart and orderIdEnd + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{OrderIDStart: &orderIdStart, OrderIDEnd: &orderIdEnd}); err != nil { + return err + } else if len(CDRs) != 8 { + return fmt.Errorf("Filter on OrderIDStart OrderIDEnd, unexpected number of CDRs returned: %d", len(CDRs)) + } + var timeStart, timeEnd time.Time + // Filter on timeStart + timeStart = time.Date(2015, 12, 28, 0, 0, 0, 0, time.UTC) + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{AnswerTimeStart: &timeStart}); err != nil { + return err + } else if len(CDRs) != 3 { + return fmt.Errorf("Filter on AnswerTimeStart, unexpected number of CDRs returned: %d", len(CDRs)) + } + // Filter on timeStart and timeEnd + timeEnd = time.Date(2015, 12, 29, 0, 0, 0, 0, time.UTC) + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { + return err + } else if len(CDRs) != 2 { + return fmt.Errorf("Filter on AnswerTimeStart AnswerTimeEnd, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on MinPDD + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinPDD: "20ms"}); err != nil { + return err + } else if len(CDRs) != 7 { + return fmt.Errorf("Filter on MinPDD, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on maxPdd + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MaxPDD: "1s"}); err != nil { + return err + } else if len(CDRs) != 8 { + return fmt.Errorf("Filter on MaxPDD, unexpected number of CDRs returned: %+v", CDRs) + } + // Filter on minPdd, maxPdd + if CDRs, _, err := cdrStorage.GetCDRs(&utils.CDRsFilter{MinPDD: "10ms", MaxPDD: "1s"}); err != nil { + return err + } else if len(CDRs) != 6 { + return fmt.Errorf("Filter on MinPDD MaxPDD, 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}); err != nil { + return err + } else if len(CDRs) != 1 { + return fmt.Errorf("Filter on RequestTypes AnswerTimeStart AnswerTimeEnd, unexpected number of CDRs returned: %+v", CDRs) + } + return nil +} diff --git a/engine/storage_interface.go b/engine/storage_interface.go index ee67ad681..0f10bc6a5 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -96,12 +96,11 @@ type AccountingStorage interface { type CdrStorage interface { Storage - SetCdr(*StoredCdr) error - SetRatedCdr(*StoredCdr) error - LogCallCost(cgrid, source, runid string, cc *CallCost) error - GetCallCostLog(cgrid, source, runid string) (*CallCost, error) - GetStoredCdrs(*utils.CdrsFilter) ([]*StoredCdr, int64, error) - RemStoredCdrs([]string) error + SetCDR(*CDR, bool) error + LogCallCost(cgrid, runid, source string, cc *CallCost) error + GetCallCostLog(cgrid, runid string) (*CallCost, error) + GetCDRs(*utils.CDRsFilter) ([]*CDR, int64, error) + RemCDRs([]string) error } type LogStorage interface { diff --git a/engine/storage_mongo.go b/engine/storage_mongo_datadb.go similarity index 95% rename from engine/storage_mongo.go rename to engine/storage_mongo_datadb.go index a45efc1cf..ad6fc6e75 100644 --- a/engine/storage_mongo.go +++ b/engine/storage_mongo_datadb.go @@ -24,37 +24,61 @@ import ( "errors" "fmt" "io/ioutil" + "strings" "github.com/cgrates/cgrates/cache2go" "github.com/cgrates/cgrates/utils" - "gopkg.in/mgo.v2" - "gopkg.in/mgo.v2/bson" ) const ( colDst = "destinations" colAct = "actions" - colApl = "actionplans" + colApl = "action_plans" colTsk = "tasks" - colAtr = "actiontriggers" - colRpl = "ratingplans" - colRpf = "ratingprofiles" + colAtr = "action_triggers" + colRpl = "rating_plans" + colRpf = "rating_profiles" colAcc = "accounts" - colShg = "sharedgroups" - colLcr = "lcrrules" - colDcs = "derivedchargers" + colShg = "shared_groups" + colLcr = "lcr_rules" + colDcs = "derived_chargers" colAls = "aliases" - colStq = "statsqeues" + colStq = "stat_qeues" colPbs = "pubsub" colUsr = "users" - colCrs = "cdrstats" - colLht = "loadhistory" - colLogAtr = "actiontriggerslogs" - colLogApl = "actionplanlogs" - colLogErr = "errorlogs" - colCdrs = "cdrs" + colCrs = "cdr_stats" + colLht = "load_history" + colLogAtr = "action_trigger_logs" + colLogApl = "action_plan_logs" + colLogErr = "error_logs" +) + +var ( + CGRIDLow = strings.ToLower(utils.CGRID) + RunIDLow = strings.ToLower(utils.MEDI_RUNID) + OrderIDLow = strings.ToLower(utils.ORDERID) + ToRLow = strings.ToLower(utils.TOR) + CDRHostLow = strings.ToLower(utils.CDRHOST) + CDRSourceLow = strings.ToLower(utils.CDRSOURCE) + RequestTypeLow = strings.ToLower(utils.REQTYPE) + DirectionLow = strings.ToLower(utils.DIRECTION) + TenantLow = strings.ToLower(utils.TENANT) + CategoryLow = strings.ToLower(utils.CATEGORY) + AccountLow = strings.ToLower(utils.ACCOUNT) + SubjectLow = strings.ToLower(utils.SUBJECT) + SupplierLow = strings.ToLower(utils.SUPPLIER) + DisconnectCauseLow = strings.ToLower(utils.DISCONNECT_CAUSE) + SetupTimeLow = strings.ToLower(utils.SETUP_TIME) + AnswerTimeLow = strings.ToLower(utils.ANSWER_TIME) + CreatedAtLow = strings.ToLower(utils.CreatedAt) + UpdatedAtLow = strings.ToLower(utils.UpdatedAt) + UsageLow = strings.ToLower(utils.USAGE) + PDDLow = strings.ToLower(utils.PDD) + CostDetailsLow = strings.ToLower(utils.COST_DETAILS) + DestinationLow = strings.ToLower(utils.DESTINATION) + CostLow = strings.ToLower(utils.COST) ) type MongoStorage struct { @@ -192,13 +216,13 @@ func NewMongoStorage(host, port, db, user, pass string) (*MongoStorage, error) { } } index = mgo.Index{ - Key: []string{"cgrid", "cdrsource", "mediationrunid"}, + Key: []string{CGRIDLow, RunIDLow}, Unique: true, DropDups: false, Background: false, Sparse: false, } - collections = []string{colCdrs} + collections = []string{utils.TBL_CDRS} for _, col := range collections { if err = ndb.C(col).EnsureIndex(index); err != nil { return nil, err diff --git a/engine/storage_mongo_local_test.go b/engine/storage_mongo_local_test.go deleted file mode 100644 index 917559f67..000000000 --- a/engine/storage_mongo_local_test.go +++ /dev/null @@ -1,973 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2012-2015 ITsysCOM - -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 ( - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" -) - -var mongoDb *MongoStorage - -func TestMongoCreateTables(t *testing.T) { - if !*testLocal { - return - } - cgrConfig, _ := config.NewDefaultCGRConfig() - var err error - if mongoDb, err = NewMongoStorage("localhost", "27017", cgrConfig.StorDBName, cgrConfig.StorDBUser, cgrConfig.StorDBPass); err != nil { - t.Error("Error on opening database connection: ", err) - } -} - -func TestMongoSetGetTPTiming(t *testing.T) { - if !*testLocal { - return - } - tm := TpTiming{Tpid: utils.TEST_SQL, Tag: "ALWAYS", Time: "00:00:00"} - if err := mongoDb.SetTpTimings([]TpTiming{tm}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.Tag); err != nil { - t.Error(err.Error()) - } else if !modelEqual(tm, tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", tm, tmgs[0]) - } - // Update - tm.Time = "00:00:01" - if err := mongoDb.SetTpTimings([]TpTiming{tm}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.Tag); err != nil { - t.Error(err.Error()) - } else if !modelEqual(tm, tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", tm, tmgs[0]) - } -} - -func TestMongoSetGetTPDestination(t *testing.T) { - if !*testLocal { - return - } - dst := []TpDestination{ - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49"}, - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49151"}, - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49176"}, - } - if err := mongoDb.SetTpDestinations(dst); err != nil { - t.Error(err.Error()) - } - storData, err := mongoDb.GetTpDestinations(utils.TEST_SQL, utils.TEST_SQL) - dsts, err := TpDestinations(storData).GetDestinations() - expected := &Destination{Id: utils.TEST_SQL, Prefixes: []string{"+49", "+49151", "+49176"}} - if err != nil { - t.Error(err.Error()) - } else if !modelEqual(*expected, *dsts[utils.TEST_SQL]) { - t.Errorf("Expecting: %+v, received: %+v", expected, dsts[utils.TEST_SQL]) - } -} - -func TestMongoSetGetTPRates(t *testing.T) { - if !*testLocal { - return - } - RT_ID := "RT_1" - rtSlots := []*utils.RateSlot{ - &utils.RateSlot{ConnectFee: 0.02, Rate: 0.01, RateUnit: "60s", RateIncrement: "60s", GroupIntervalStart: "0s"}, - &utils.RateSlot{ConnectFee: 0.00, Rate: 0.005, RateUnit: "60s", RateIncrement: "1s", GroupIntervalStart: "60s"}, - } - for _, rs := range rtSlots { - rs.SetDurations() - } - rates := &utils.TPRate{ - TPid: utils.TEST_SQL, - RateId: RT_ID, - RateSlots: rtSlots, - } - mRates := APItoModelRate(rates) - if err := mongoDb.SetTpRates(mRates); err != nil { - t.Error(err.Error()) - } - if rts, err := mongoDb.GetTpRates(utils.TEST_SQL, RT_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mRates[0], rts[0]) { - t.Errorf("Expecting: %+v, received: %+v", mRates, rts) - } -} - -func TestMongoSetGetTPDestinationRates(t *testing.T) { - if !*testLocal { - return - } - DR_ID := "DR_1" - dr := &utils.DestinationRate{DestinationId: "DST_1", RateId: "RT_1", RoundingMethod: "*up", RoundingDecimals: 4} - - eDrs := &utils.TPDestinationRate{TPid: utils.TEST_SQL, DestinationRateId: DR_ID, DestinationRates: []*utils.DestinationRate{dr}} - mdrs := APItoModelDestinationRate(eDrs) - if err := mongoDb.SetTpDestinationRates(mdrs); err != nil { - t.Error(err.Error()) - } - if drs, err := mongoDb.GetTpDestinationRates(utils.TEST_SQL, DR_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdrs[0], drs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdrs, drs) - } -} - -func TestMongoSetGetTPRatingPlans(t *testing.T) { - if !*testLocal { - return - } - RP_ID := "RP_1" - rbBinding := &utils.TPRatingPlanBinding{DestinationRatesId: "DR_1", TimingId: "TM_1", Weight: 10.0} - rp := &utils.TPRatingPlan{ - TPid: utils.TEST_SQL, - RatingPlanId: RP_ID, - RatingPlanBindings: []*utils.TPRatingPlanBinding{rbBinding}, - } - mrp := APItoModelRatingPlan(rp) - if err := mongoDb.SetTpRatingPlans(mrp); err != nil { - t.Error(err.Error()) - } - if drps, err := mongoDb.GetTpRatingPlans(utils.TEST_SQL, RP_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], drps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, drps) - } -} - -func TestMongoSetGetTPRatingProfiles(t *testing.T) { - if !*testLocal { - return - } - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RP_1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - mrp := APItoModelRatingProfile(rp) - if err := mongoDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mongoDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], rps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, rps) - } - -} - -func TestMongoSetGetTPSharedGroups(t *testing.T) { - if !*testLocal { - return - } - SG_ID := "SG_1" - tpSgs := &utils.TPSharedGroups{ - TPid: utils.TEST_SQL, - SharedGroupsId: SG_ID, - SharedGroups: []*utils.TPSharedGroup{ - &utils.TPSharedGroup{Account: "dan", Strategy: "*lowest_first", RatingSubject: "lowest_rates"}, - }, - } - mSgs := APItoModelSharedGroup(tpSgs) - if err := mongoDb.SetTpSharedGroups(mSgs); err != nil { - t.Error(err.Error()) - } - if sgs, err := mongoDb.GetTpSharedGroups(utils.TEST_SQL, SG_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mSgs[0], sgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mSgs, sgs) - } -} - -func TestMongoSetGetTPCdrStats(t *testing.T) { - if !*testLocal { - return - } - CS_ID := "CDRSTATS_1" - setCS := &utils.TPCdrStats{ - TPid: utils.TEST_SQL, - CdrStatsId: CS_ID, - CdrStats: []*utils.TPCdrStat{ - &utils.TPCdrStat{QueueLength: "10", TimeWindow: "10m", Metrics: "ASR", Tenants: "cgrates.org", Categories: "call"}, - }, - } - mcs := APItoModelCdrStat(setCS) - if err := mongoDb.SetTpCdrStats(mcs); err != nil { - t.Error(err.Error()) - } - if cs, err := mongoDb.GetTpCdrStats(utils.TEST_SQL, CS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mcs[0], cs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mcs, cs) - } -} - -func TestMongoSetGetTPDerivedChargers(t *testing.T) { - if !*testLocal { - return - } - dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", - UsageField: "cgr_duration", SupplierField: "^supplier1"} - dcs := &utils.TPDerivedChargers{TPid: utils.TEST_SQL, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: []*utils.TPDerivedCharger{dc}} - - mdcs := APItoModelDerivedCharger(dcs) - if err := mongoDb.SetTpDerivedChargers(mdcs); err != nil { - t.Error(err.Error()) - } - if rDCs, err := mongoDb.GetTpDerivedChargers(&mdcs[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdcs[0], rDCs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdcs, rDCs) - } -} - -func TestMongoSetGetTPActions(t *testing.T) { - if !*testLocal { - return - } - ACTS_ID := "PREPAID_10" - acts := []*utils.TPAction{ - &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Directions: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationIds: "*any", BalanceWeight: 10, Weight: 10}} - tpActions := &utils.TPActions{TPid: utils.TEST_SQL, ActionsId: ACTS_ID, Actions: acts} - mas := APItoModelAction(tpActions) - if err := mongoDb.SetTpActions(mas); err != nil { - t.Error(err.Error()) - } - if rTpActs, err := mongoDb.GetTpActions(utils.TEST_SQL, ACTS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mas[0], rTpActs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mas, rTpActs) - } -} - -func TestMongoTPActionTimings(t *testing.T) { - if !*testLocal { - return - } - AP_ID := "AP_1" - ap := &utils.TPActionPlan{ - TPid: utils.TEST_SQL, - ActionPlanId: AP_ID, - ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, - } - maps := APItoModelActionPlan(ap) - if err := mongoDb.SetTpActionPlans(maps); err != nil { - t.Error(err.Error()) - } - if rAP, err := mongoDb.GetTpActionPlans(utils.TEST_SQL, AP_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(maps[0], rAP[0]) { - t.Errorf("Expecting: %+v, received: %+v", maps, rAP) - } -} - -func TestMongoSetGetTPActionTriggers(t *testing.T) { - if !*testLocal { - return - } - atrg := &utils.TPActionTrigger{ - Id: "MY_FIRST_ATGR", - BalanceType: "*monetary", - BalanceDirections: "*out", - ThresholdType: "*min_balance", - ThresholdValue: 2.0, - Recurrent: true, - BalanceDestinationIds: "*any", - Weight: 10.0, - ActionsId: "LOG_BALANCE", - } - atrgs := &utils.TPActionTriggers{ - TPid: utils.TEST_SQL, - ActionTriggersId: "MY_FIRST_ATGR", - ActionTriggers: []*utils.TPActionTrigger{atrg}, - } - matrg := APItoModelActionTrigger(atrgs) - if err := mongoDb.SetTpActionTriggers(matrg); err != nil { - t.Error("Unexpected error: ", err.Error()) - } - if rcvMpAtrgs, err := mongoDb.GetTpActionTriggers(utils.TEST_SQL, "MY_FIRST_ATGR"); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if !modelEqual(matrg[0], rcvMpAtrgs[0]) { - t.Errorf("Expecting: %v, received: %v", matrg, rcvMpAtrgs) - } -} - -func TestMongoSetGetTpAccountActions(t *testing.T) { - if !*testLocal { - return - } - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := mongoDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mongoDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if !modelEqual(*maa, aas[0]) { - t.Errorf("Expecting: %+v, received: %+v", maa, aas) - } -} - -func TestMongoGetTPIds(t *testing.T) { - if !*testLocal { - return - } - eTPIds := []string{utils.TEST_SQL} - if tpIds, err := mongoDb.GetTpIds(); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(eTPIds, tpIds) { - t.Errorf("Expecting: %+v, received: %+v", eTPIds, tpIds) - } -} - -func TestMongoRemoveTPData(t *testing.T) { - if !*testLocal { - return - } - // Create Timings - tm := &utils.ApierTPTiming{TPid: utils.TEST_SQL, TimingId: "ALWAYS", Time: "00:00:00"} - tms := APItoModelTiming(tm) - if err := mongoDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Remove Timings - if err := mongoDb.RemTpData(utils.TBL_TP_TIMINGS, utils.TEST_SQL, map[string]string{"tag": tm.TimingId}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tmgs) != 0 { - t.Errorf("Timings should be empty, got instead: %+v", tmgs) - } - // Create RatingProfile - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - mrp := APItoModelRatingProfile(rp) - if err := mongoDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mongoDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Remove RatingProfile - if err := mongoDb.RemTpData(utils.TBL_TP_RATE_PROFILES, rp.TPid, map[string]string{"loadid": rp.LoadId, "direction": rp.Direction, "tenant": rp.Tenant, "category": rp.Category, "subject": rp.Subject}); err != nil { - t.Error(err.Error()) - } - if rps, err := mongoDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rps) != 0 { - t.Errorf("RatingProfiles different than 0: %+v", rps) - } - // Create AccountActions - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := mongoDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mongoDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove AccountActions - if err := mongoDb.RemTpData(utils.TBL_TP_ACCOUNT_ACTIONS, aa.TPid, map[string]string{"loadid": aa.LoadId, "tenant": aa.Tenant, "account": aa.Account}); err != nil { - t.Error(err.Error()) - } - if aas, err := mongoDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } - // Create again so we can test complete TP removal - if err := mongoDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Create RatingProfile - if err := mongoDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mongoDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Create AccountActions - if err := mongoDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mongoDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove TariffPlan completely - if err := mongoDb.RemTpData("", utils.TEST_SQL, nil); err != nil { - t.Error(err.Error()) - } - // Make sure we have removed it - if tms, err := mongoDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tms) != 0 { - t.Errorf("Non empty timings: %+v", tms) - } - if rpfs, err := mongoDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rpfs) != 0 { - t.Errorf("Non empty rpfs: %+v", rpfs) - } - if aas, err := mongoDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } -} - -func TestMongoSetCdr(t *testing.T) { - if !*testLocal { - return - } - cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: utils.TEST_SQL} - - cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} { - if err := mongoDb.SetCdr(cdr.AsStoredCdr("")); err != nil { - t.Error(err.Error()) - } - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mongoDb.SetCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestMongoSetRatedCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: "wholesale_run", Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mongoDb.SetRatedCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestMongoCallCost(t *testing.T) { - if !*testLocal { - return - } - cgrId := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cc := &CallCost{ - Direction: "*out", - Category: "call", - Tenant: "cgrates.org", - Subject: "91001", - Account: "8001", - Destination: "1002", - TOR: utils.VOICE, - Timespans: []*TimeSpan{ - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 40, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - }, - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 30, 0, time.UTC), - }, - }, - } - if err := mongoDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := mongoDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if cc.Cost != ccRcv.Cost { - t.Errorf("Expecting call cost:\n%+v,\nreceived:\n%+v", cc.Timespans[0], ccRcv.Timespans[0]) - } - // UPDATE test here - cc.Category = "premium_call" - if err := mongoDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := mongoDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if cc.Cost != ccRcv.Cost { - t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) - } -} - -func TestMongoGetStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - var timeStart, timeEnd time.Time - // All CDRs, no filter - if storedCdrs, _, err := mongoDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 20 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Count ALL - if storedCdrs, count, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Count: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } else if count != 20 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Limit 5 - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Offset 5 - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Offset with limit 2 - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(2), Offset: utils.IntPointer(5)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on cgrids - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Count on CGRIDS - if _, count, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 3 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on cgrids plus reqType - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Count on multiple filter - if _, count, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 1 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on runId - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{RunIds: []string{utils.DEFAULT_RUNID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 14 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on TOR - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple TOR - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS, utils.VOICE}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 15 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on cdrHost - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple cdrHost - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.1", "192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 15 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on cdrSource - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple cdrSource - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN", "UNKNOWN2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on reqType - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple reqType - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID, utils.META_PSEUDOPREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 6 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on direction - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Directions: []string{"*out"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 15 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on tenant - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple tenants - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com", "cgrates.org"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 15 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on category - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple categories - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call", "call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 15 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on account - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 6 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple account - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1001", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 13 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on subject - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple subject - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 6 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on destPrefix - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on multiple destPrefixes - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"1001", "+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on ratedAccount - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{RatedAccounts: []string{"8001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on ratedSubject - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{RatedSubjects: []string{"91001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on ignoreRated - var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } else { - for _, cdr := range storedCdrs { - if cdr.OrderId < orderIdStart { - orderIdStart = cdr.OrderId - } - if cdr.OrderId > orderIdEnd { - orderIdEnd = cdr.OrderId - } - } - } - // Filter on orderIdStart - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 20 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on orderIdStart and orderIdEnd - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart, OrderIdEnd: orderIdEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 20 { // TODO: find mongo equivalent - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on timeStart - timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 6 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on timeStart and timeEnd - timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on minPdd - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(float64(3 * time.Second))}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on maxPdd - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{MaxPdd: utils.Float64Pointer(float64(3 * time.Second))}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 13 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on minPdd, maxPdd - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(float64(3 * time.Second)), MaxPdd: utils.Float64Pointer(float64(5 * time.Second))}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Combined filter - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on ignoreDerived - if storedCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { // ToDo: Recheck this value - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } -} - -func TestMongoRemStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - cgrIdB1 := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mongoDb.RemStoredCdrs([]string{cgrIdB1}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := mongoDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 20 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - tm, _ := utils.ParseTimeDetectLayout("2013-11-08T08:42:20Z", "") - cgrIdA1 := utils.Sha1("aaa1", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-08T08:42:22Z", "") - cgrIdA2 := utils.Sha1("aaa2", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:24Z", "") - cgrIdA3 := utils.Sha1("aaa3", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:21Z", "") - cgrIdA4 := utils.Sha1("aaa4", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:25Z", "") - cgrIdA5 := utils.Sha1("aaa5", tm.String()) - cgrIdB2 := utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cgrIdB3 := utils.Sha1("bbb3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mongoDb.RemStoredCdrs([]string{cgrIdA1, cgrIdA2, cgrIdA3, cgrIdA4, cgrIdA5, - cgrIdB2, cgrIdB3}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := mongoDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 20 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } -} - -// Make sure that what we get is what we set -func TestMongoStoreRestoreCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr := &StoredCdr{TOR: utils.VOICE, AccId: "ccc1", CdrHost: "192.168.1.1", CdrSource: "TEST_CDR", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr.CgrId = utils.Sha1(strCdr.AccId, strCdr.SetupTime.String()) - if err := mongoDb.SetCdr(strCdr); err != nil { - t.Error(err.Error()) - } - if err := mongoDb.SetRatedCdr(strCdr); err != nil { - t.Error(err.Error()) - } - // Check RawCdr - if rcvCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - !strCdr.SetupTime.Equal(rcvCdr.SetupTime) || - !strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } - // Check RatedCdr - if rcvCdrs, _, err := mongoDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - //!strCdr.SetupTime.Equal(rcvCdr.SetupTime) || // FixMe - //!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || // FixMe - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - strCdr.Cost != rcvCdr.Cost || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } -} diff --git a/engine/storage_mongo_tp.go b/engine/storage_mongo_stordb.go similarity index 79% rename from engine/storage_mongo_tp.go rename to engine/storage_mongo_stordb.go index 7a1eda6b4..9ef4333a9 100644 --- a/engine/storage_mongo_tp.go +++ b/engine/storage_mongo_stordb.go @@ -698,46 +698,46 @@ func (ms *MongoStorage) LogActionTiming(source string, at *ActionTiming, as Acti }{at, as, time.Now(), source}) } -func (ms *MongoStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) error { - s := &StoredCdr{ - CgrId: cgrid, - CdrSource: source, - MediationRunId: runid, - CostDetails: cc, +func (ms *MongoStorage) LogCallCost(cgrid, runid, source string, cc *CallCost) error { + return ms.db.C(utils.TBLSMCosts).Insert(&SMCost{CGRID: cgrid, RunID: runid, CostSource: source, CostDetails: cc}) +} + +func (ms *MongoStorage) GetCallCostLog(cgrid, runid string) (cc *CallCost, err error) { + var result SMCost + if err = ms.db.C(utils.TBLSMCosts).Find(bson.M{CGRIDLow: cgrid, RunIDLow: runid}).One(&result); err != nil { + return nil, err } - _, err := ms.db.C(colCdrs).Upsert(bson.M{"cgrid": cgrid, "cdrsource": source, "mediationrunid": runid}, s) - return err + return result.CostDetails, nil } -func (ms *MongoStorage) GetCallCostLog(cgrid, source, runid string) (cc *CallCost, err error) { - result := StoredCdr{} - err = ms.db.C(colCdrs).Find(bson.M{"cgrid": cgrid, "cdrsource": source, "mediationrunid": runid}).One(&result) - cc = result.CostDetails - return -} - -func (ms *MongoStorage) SetCdr(cdr *StoredCdr) error { - _, err := ms.db.C(colCdrs).Upsert(bson.M{"cgrid": cdr.CgrId, "mediationrunid": cdr.MediationRunId}, cdr) - return err -} - -func (ms *MongoStorage) SetRatedCdr(storedCdr *StoredCdr) error { - _, err := ms.db.C(colCdrs).Upsert(bson.M{"cgrid": storedCdr.CgrId, "mediationrunid": storedCdr.MediationRunId}, storedCdr) +func (ms *MongoStorage) SetCDR(cdr *CDR, allowUpdate bool) (err error) { + if cdr.OrderID == 0 { + cdr.OrderID = time.Now().UnixNano() + } + if allowUpdate { + _, err = ms.db.C(utils.TBL_CDRS).Upsert(bson.M{CGRIDLow: cdr.CGRID, RunIDLow: cdr.RunID}, cdr) + } else { + err = ms.db.C(utils.TBL_CDRS).Insert(cdr) + } return err } // Remove CDR data out of all CDR tables based on their cgrid -func (ms *MongoStorage) RemStoredCdrs(cgrIds []string) error { +func (ms *MongoStorage) RemCDRs(cgrIds []string) error { if len(cgrIds) == 0 { return nil } - _, err := ms.db.C(colCdrs).UpdateAll(bson.M{"cgrid": bson.M{"$in": cgrIds}}, bson.M{"$set": bson.M{"deleted_at": time.Now()}}) + _, err := ms.db.C(utils.TBL_CDRS).UpdateAll(bson.M{CGRIDLow: bson.M{"$in": cgrIds}}, bson.M{"$set": bson.M{"deleted_at": time.Now()}}) return err } func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { for k, v := range filters { switch value := v.(type) { + case *int64: + if value == nil { + delete(filters, k) + } case *float64: if value == nil { delete(filters, k) @@ -746,6 +746,10 @@ func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { if value == nil { delete(filters, k) } + case *time.Duration: + if value == nil { + delete(filters, k) + } case []string: if len(value) == 0 { delete(filters, k) @@ -759,62 +763,89 @@ func (ms *MongoStorage) cleanEmptyFilters(filters bson.M) { } } -func (ms *MongoStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, int64, error) { +func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter) ([]*CDR, int64, error) { + var minPDD, maxPDD, minUsage, maxUsage *time.Duration + if len(qryFltr.MinPDD) != 0 { + if parsed, err := utils.ParseDurationWithSecs(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 { + return nil, 0, err + } else { + maxPDD = &parsed + } + } + if len(qryFltr.MinUsage) != 0 { + if parsed, err := utils.ParseDurationWithSecs(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 { + return nil, 0, err + } else { + maxUsage = &parsed + } + } filters := bson.M{ - "cgrid": bson.M{"$in": qryFltr.CgrIds, "$nin": qryFltr.NotCgrIds}, - "mediationrunid": bson.M{"$in": qryFltr.RunIds, "$nin": qryFltr.NotRunIds}, - "tor": bson.M{"$in": qryFltr.Tors, "$nin": qryFltr.NotTors}, - "cdrhost": bson.M{"$in": qryFltr.CdrHosts, "$nin": qryFltr.NotCdrHosts}, - "cdrsource": bson.M{"$in": qryFltr.CdrSources, "$nin": qryFltr.NotCdrSources}, - "reqtype": bson.M{"$in": qryFltr.ReqTypes, "$nin": qryFltr.NotReqTypes}, - "direction": bson.M{"$in": qryFltr.Directions, "$nin": qryFltr.NotDirections}, - "tenant": bson.M{"$in": qryFltr.Tenants, "$nin": qryFltr.NotTenants}, - "category": bson.M{"$in": qryFltr.Categories, "$nin": qryFltr.NotCategories}, - "account": bson.M{"$in": qryFltr.Accounts, "$nin": qryFltr.NotAccounts}, - "subject": bson.M{"$in": qryFltr.Subjects, "$nin": qryFltr.NotSubjects}, - "supplier": bson.M{"$in": qryFltr.Suppliers, "$nin": qryFltr.NotSuppliers}, - "disconnect_cause": bson.M{"$in": qryFltr.DisconnectCauses, "$nin": qryFltr.NotDisconnectCauses}, - "setuptime": bson.M{"$gte": qryFltr.SetupTimeStart, "$lt": qryFltr.SetupTimeEnd}, - "answertime": bson.M{"$gte": qryFltr.AnswerTimeStart, "$lt": qryFltr.AnswerTimeEnd}, - "created_at": bson.M{"$gte": qryFltr.CreatedAtStart, "$lt": qryFltr.CreatedAtEnd}, - "updated_at": bson.M{"$gte": qryFltr.UpdatedAtStart, "$lt": qryFltr.UpdatedAtEnd}, - "usage": bson.M{"$gte": qryFltr.MinUsage, "$lt": qryFltr.MaxUsage}, - "pdd": bson.M{"$gte": qryFltr.MinPdd, "$lt": qryFltr.MaxPdd}, - "costdetails.account": bson.M{"$in": qryFltr.RatedAccounts, "$nin": qryFltr.NotRatedAccounts}, - "costdetails.subject": bson.M{"$in": qryFltr.RatedSubjects, "$nin": qryFltr.NotRatedSubjects}, + 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}, + //CostDetailsLow + "." + AccountLow: bson.M{"$in": qryFltr.RatedAccounts, "$nin": qryFltr.NotRatedAccounts}, + //CostDetailsLow + "." + SubjectLow: bson.M{"$in": qryFltr.RatedSubjects, "$nin": qryFltr.NotRatedSubjects}, } //file, _ := ioutil.TempFile(os.TempDir(), "debug") //file.WriteString(fmt.Sprintf("FILTER: %v\n", utils.ToIJSON(qryFltr))) //file.WriteString(fmt.Sprintf("BEFORE: %v\n", utils.ToIJSON(filters))) ms.cleanEmptyFilters(filters) - - /*if qryFltr.OrderIdStart != 0 { - filters["id"] = bson.M{"$gte": qryFltr.OrderIdStart} + if len(qryFltr.DestinationPrefixes) != 0 { + var regexpRule string + for _, prefix := range qryFltr.DestinationPrefixes { + if len(prefix) == 0 { + continue + } + if len(regexpRule) != 0 { + regexpRule += "|" + } + regexpRule += "^(" + prefix + ")" + } + if _, hasIt := filters["$and"]; !hasIt { + filters["$and"] = make([]bson.M, 0) + } + filters["$and"] = append(filters["$and"].([]bson.M), bson.M{DestinationLow: bson.RegEx{Pattern: regexpRule}}) // $and gathers all rules not fitting top level query } - if qryFltr.OrderIdEnd != 0 { - if m, ok := filters["id"]; ok { - m.(bson.M)["$gte"] = qryFltr.OrderIdStart - } else { - filters["id"] = bson.M{"$gte": qryFltr.OrderIdStart} + if len(qryFltr.NotDestinationPrefixes) != 0 { + if _, hasIt := filters["$and"]; !hasIt { + filters["$and"] = make([]bson.M, 0) } - }*/ - - if len(qryFltr.DestPrefixes) != 0 { - var regexes []bson.RegEx - for _, prefix := range qryFltr.DestPrefixes { - regexes = append(regexes, bson.RegEx{Pattern: regexp.QuoteMeta(prefix) + ".*"}) - } - filters["destination"] = bson.M{"$in": regexes} - } - if len(qryFltr.NotDestPrefixes) != 0 { - var notRegexes []bson.RegEx - for _, prefix := range qryFltr.DestPrefixes { - notRegexes = append(notRegexes, bson.RegEx{Pattern: regexp.QuoteMeta(prefix) + ".*"}) - } - if m, ok := filters["destination"]; ok { - m.(bson.M)["$nin"] = notRegexes - } else { - filters["destination"] = bson.M{"$nin": notRegexes} + for _, prefix := range qryFltr.NotDestinationPrefixes { + if len(prefix) == 0 { + continue + } + filters["$and"] = append(filters["$and"].([]bson.M), bson.M{DestinationLow: bson.RegEx{Pattern: "^(?!" + prefix + ")"}}) } } @@ -836,24 +867,24 @@ func (ms *MongoStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { - filters["cost"] = bson.M{"$gte": *qryFltr.MinCost} + filters[CostLow] = bson.M{"$gte": *qryFltr.MinCost} } else if *qryFltr.MinCost == 0.0 && *qryFltr.MaxCost == -1.0 { // Special case when we want to skip errors filters["$or"] = []bson.M{ - bson.M{"cost": bson.M{"$gte": 0.0}}, + bson.M{CostLow: bson.M{"$gte": 0.0}}, } } else { - filters["cost"] = bson.M{"$gte": *qryFltr.MinCost, "$lt": *qryFltr.MaxCost} + filters[CostLow] = bson.M{"$gte": *qryFltr.MinCost, "$lt": *qryFltr.MaxCost} } } else if qryFltr.MaxCost != nil { if *qryFltr.MaxCost == -1.0 { // Non-rated CDRs - filters["cost"] = 0.0 // Need to include it otherwise all CDRs will be returned + filters[CostLow] = 0.0 // Need to include it otherwise all CDRs will be returned } else { // Above limited CDRs, since MinCost is empty, make sure we query also NULL cost - filters["cost"] = bson.M{"$lt": *qryFltr.MaxCost} + filters[CostLow] = bson.M{"$lt": *qryFltr.MaxCost} } } //file.WriteString(fmt.Sprintf("AFTER: %v\n", utils.ToIJSON(filters))) //file.Close() - q := ms.db.C(colCdrs).Find(filters) + q := ms.db.C(utils.TBL_CDRS).Find(filters) if qryFltr.Paginator.Limit != nil { q = q.Limit(*qryFltr.Paginator.Limit) } @@ -867,11 +898,10 @@ func (ms *MongoStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, } return nil, int64(cnt), nil } - // Execute query iter := q.Iter() - var cdrs []*StoredCdr - cdr := StoredCdr{} + var cdrs []*CDR + cdr := CDR{} for iter.Next(&cdr) { clone := cdr cdrs = append(cdrs, &clone) diff --git a/engine/storage_mysql.go b/engine/storage_mysql.go index 539a242e1..b59b1ce99 100644 --- a/engine/storage_mysql.go +++ b/engine/storage_mysql.go @@ -19,15 +19,16 @@ along with this program. If not, see package engine import ( - "encoding/json" "fmt" - "path" - "time" - "github.com/cgrates/cgrates/utils" + _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) +type MySQLStorage struct { + *SQLStorage +} + func NewMySQLStorage(host, port, name, user, password string, maxConn, maxIdleConn int) (*MySQLStorage, error) { connectString := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true", user, password, host, port, name) db, err := gorm.Open("mysql", connectString) @@ -43,81 +44,3 @@ func NewMySQLStorage(host, port, name, user, password string, maxConn, maxIdleCo return &MySQLStorage{&SQLStorage{Db: db.DB(), db: db}}, nil } - -type MySQLStorage struct { - *SQLStorage -} - -func (self *MySQLStorage) Flush(scriptsPath string) (err error) { - for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} { - if err := self.CreateTablesFromScript(path.Join(scriptsPath, scriptName)); err != nil { - return err - } - } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := self.Db.Query(fmt.Sprintf("SELECT 1 FROM %s", tbl)); err != nil { - return err - } - } - return nil -} - -func (self *MySQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (err error) { - if cc == nil { - return nil - } - tss, err := json.Marshal(cc.Timespans) - if err != nil { - utils.Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err)) - return err - } - _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,tor,direction,tenant,category,account,subject,destination,cost,timespans,cost_source,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s',%f,'%s','%s','%s') ON DUPLICATE KEY UPDATE tor=values(tor),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),cost=values(cost),timespans=values(timespans),cost_source=values(cost_source),updated_at='%s'", - utils.TBL_COST_DETAILS, - cgrid, - runid, - cc.TOR, - cc.Direction, - cc.Tenant, - cc.Category, - cc.Account, - cc.Subject, - cc.Destination, - cc.Cost, - tss, - source, - time.Now().Format(time.RFC3339), - time.Now().Format(time.RFC3339))) - if err != nil { - utils.Logger.Err(fmt.Sprintf("failed to execute insert statement: %v", err)) - return err - } - return nil -} - -func (self *MySQLStorage) SetRatedCdr(storedCdr *StoredCdr) (err error) { - _, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,pdd,supplier,disconnect_cause,cost,extra_info,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,%v,'%s','%s',%f,'%s','%s') ON DUPLICATE KEY UPDATE reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),pdd=values(pdd),cost=values(cost),supplier=values(supplier),disconnect_cause=values(disconnect_cause),extra_info=values(extra_info), updated_at='%s'", - utils.TBL_RATED_CDRS, - storedCdr.CgrId, - storedCdr.MediationRunId, - storedCdr.ReqType, - storedCdr.Direction, - storedCdr.Tenant, - storedCdr.Category, - storedCdr.Account, - storedCdr.Subject, - storedCdr.Destination, - storedCdr.SetupTime, - storedCdr.AnswerTime, - storedCdr.Usage.Seconds(), - storedCdr.Pdd.Seconds(), - storedCdr.Supplier, - storedCdr.DisconnectCause, - storedCdr.Cost, - storedCdr.ExtraInfo, - time.Now().Format(time.RFC3339), - time.Now().Format(time.RFC3339))) - if err != nil { - utils.Logger.Err(fmt.Sprintf("failed to execute cdr insert statement: %s", err.Error())) - } - return -} diff --git a/engine/storage_mysql_local_test.go b/engine/storage_mysql_local_test.go deleted file mode 100644 index 6f2be2799..000000000 --- a/engine/storage_mysql_local_test.go +++ /dev/null @@ -1,990 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2012-2015 ITsysCOM - -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 ( - "fmt" - "path" - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" -) - -var mysqlDb *MySQLStorage - -func TestMySQLCreateTables(t *testing.T) { - if !*testLocal { - return - } - cgrConfig, _ := config.NewDefaultCGRConfig() - var err error - if mysqlDb, err = NewMySQLStorage(cgrConfig.StorDBHost, cgrConfig.StorDBPort, cgrConfig.StorDBName, cgrConfig.StorDBUser, cgrConfig.StorDBPass, - cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns); err != nil { - t.Error("Error on opening database connection: ", err) - return - } - for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} { - if err := mysqlDb.CreateTablesFromScript(path.Join(*dataDir, "storage", utils.MYSQL, scriptName)); err != nil { - t.Error("Error on mysqlDb creation: ", err.Error()) - return // No point in going further - } - } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := mysqlDb.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { - t.Error(err.Error()) - } - } -} - -func TestMySQLSetGetTPTiming(t *testing.T) { - if !*testLocal { - return - } - tm := TpTiming{Tpid: utils.TEST_SQL, Tag: "ALWAYS", Time: "00:00:00"} - if err := mysqlDb.SetTpTimings([]TpTiming{tm}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.Tag); err != nil { - t.Error(err.Error()) - } else if !modelEqual(tm, tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", tm, tmgs[0]) - } - // Update - tm.Time = "00:00:01" - if err := mysqlDb.SetTpTimings([]TpTiming{tm}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.Tag); err != nil { - t.Error(err.Error()) - } else if !modelEqual(tm, tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", tm, tmgs[0]) - } -} - -func TestMySQLSetGetTPDestination(t *testing.T) { - if !*testLocal { - return - } - dst := []TpDestination{ - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49"}, - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49151"}, - TpDestination{Tpid: utils.TEST_SQL, Tag: utils.TEST_SQL, Prefix: "+49176"}, - } - if err := mysqlDb.SetTpDestinations(dst); err != nil { - t.Error(err.Error()) - } - storData, err := mysqlDb.GetTpDestinations(utils.TEST_SQL, utils.TEST_SQL) - dsts, err := TpDestinations(storData).GetDestinations() - expected := &Destination{Id: utils.TEST_SQL, Prefixes: []string{"+49", "+49151", "+49176"}} - if err != nil { - t.Error(err.Error()) - } else if !modelEqual(*expected, *dsts[utils.TEST_SQL]) { - t.Errorf("Expecting: %+v, received: %+v", expected, dsts[utils.TEST_SQL]) - } -} - -func TestMySQLSetGetTPRates(t *testing.T) { - if !*testLocal { - return - } - RT_ID := "RT_1" - rtSlots := []*utils.RateSlot{ - &utils.RateSlot{ConnectFee: 0.02, Rate: 0.01, RateUnit: "60s", RateIncrement: "60s", GroupIntervalStart: "0s"}, - &utils.RateSlot{ConnectFee: 0.00, Rate: 0.005, RateUnit: "60s", RateIncrement: "1s", GroupIntervalStart: "60s"}, - } - for _, rs := range rtSlots { - rs.SetDurations() - } - rates := &utils.TPRate{ - TPid: utils.TEST_SQL, - RateId: RT_ID, - RateSlots: rtSlots, - } - mRates := APItoModelRate(rates) - if err := mysqlDb.SetTpRates(mRates); err != nil { - t.Error(err.Error()) - } - if rts, err := mysqlDb.GetTpRates(utils.TEST_SQL, RT_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mRates[0], rts[0]) { - t.Errorf("Expecting: %+v, received: %+v", mRates, rts) - } -} - -func TestMySQLSetGetTPDestinationRates(t *testing.T) { - if !*testLocal { - return - } - DR_ID := "DR_1" - dr := &utils.DestinationRate{DestinationId: "DST_1", RateId: "RT_1", RoundingMethod: "*up", RoundingDecimals: 4} - - eDrs := &utils.TPDestinationRate{TPid: utils.TEST_SQL, DestinationRateId: DR_ID, DestinationRates: []*utils.DestinationRate{dr}} - mdrs := APItoModelDestinationRate(eDrs) - if err := mysqlDb.SetTpDestinationRates(mdrs); err != nil { - t.Error(err.Error()) - } - if drs, err := mysqlDb.GetTpDestinationRates(utils.TEST_SQL, DR_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdrs[0], drs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdrs, drs) - } -} - -func TestMySQLSetGetTPRatingPlans(t *testing.T) { - if !*testLocal { - return - } - RP_ID := "RP_1" - rbBinding := &utils.TPRatingPlanBinding{DestinationRatesId: "DR_1", TimingId: "TM_1", Weight: 10.0} - rp := &utils.TPRatingPlan{ - TPid: utils.TEST_SQL, - RatingPlanId: RP_ID, - RatingPlanBindings: []*utils.TPRatingPlanBinding{rbBinding}, - } - mrp := APItoModelRatingPlan(rp) - if err := mysqlDb.SetTpRatingPlans(mrp); err != nil { - t.Error(err.Error()) - } - if drps, err := mysqlDb.GetTpRatingPlans(utils.TEST_SQL, RP_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], drps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, drps) - } -} - -func TestMySQLSetGetTPRatingProfiles(t *testing.T) { - if !*testLocal { - return - } - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RP_1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - mrp := APItoModelRatingProfile(rp) - if err := mysqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mysqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], rps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, rps) - } - -} - -func TestMySQLSetGetTPSharedGroups(t *testing.T) { - if !*testLocal { - return - } - SG_ID := "SG_1" - tpSgs := &utils.TPSharedGroups{ - TPid: utils.TEST_SQL, - SharedGroupsId: SG_ID, - SharedGroups: []*utils.TPSharedGroup{ - &utils.TPSharedGroup{Account: "dan", Strategy: "*lowest_first", RatingSubject: "lowest_rates"}, - }, - } - mSgs := APItoModelSharedGroup(tpSgs) - if err := mysqlDb.SetTpSharedGroups(mSgs); err != nil { - t.Error(err.Error()) - } - if sgs, err := mysqlDb.GetTpSharedGroups(utils.TEST_SQL, SG_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mSgs[0], sgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mSgs, sgs) - } -} - -func TestMySQLSetGetTPCdrStats(t *testing.T) { - if !*testLocal { - return - } - CS_ID := "CDRSTATS_1" - setCS := &utils.TPCdrStats{ - TPid: utils.TEST_SQL, - CdrStatsId: CS_ID, - CdrStats: []*utils.TPCdrStat{ - &utils.TPCdrStat{QueueLength: "10", TimeWindow: "10m", Metrics: "ASR", Tenants: "cgrates.org", Categories: "call"}, - }, - } - mcs := APItoModelCdrStat(setCS) - if err := mysqlDb.SetTpCdrStats(mcs); err != nil { - t.Error(err.Error()) - } - if cs, err := mysqlDb.GetTpCdrStats(utils.TEST_SQL, CS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mcs[0], cs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mcs, cs) - } -} - -func TestMySQLSetGetTPDerivedChargers(t *testing.T) { - if !*testLocal { - return - } - dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", - UsageField: "cgr_duration", SupplierField: "^supplier1"} - dcs := &utils.TPDerivedChargers{TPid: utils.TEST_SQL, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: []*utils.TPDerivedCharger{dc}} - - mdcs := APItoModelDerivedCharger(dcs) - if err := mysqlDb.SetTpDerivedChargers(mdcs); err != nil { - t.Error(err.Error()) - } - if rDCs, err := mysqlDb.GetTpDerivedChargers(&mdcs[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdcs[0], rDCs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdcs, rDCs) - } -} - -func TestMySQLSetGetTPActions(t *testing.T) { - if !*testLocal { - return - } - ACTS_ID := "PREPAID_10" - acts := []*utils.TPAction{ - &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Directions: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationIds: "*any", BalanceWeight: 10, Weight: 10}} - tpActions := &utils.TPActions{TPid: utils.TEST_SQL, ActionsId: ACTS_ID, Actions: acts} - mas := APItoModelAction(tpActions) - if err := mysqlDb.SetTpActions(mas); err != nil { - t.Error(err.Error()) - } - if rTpActs, err := mysqlDb.GetTpActions(utils.TEST_SQL, ACTS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mas[0], rTpActs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mas, rTpActs) - } -} - -func TestMySQLTPActionTimings(t *testing.T) { - if !*testLocal { - return - } - AP_ID := "AP_1" - ap := &utils.TPActionPlan{ - TPid: utils.TEST_SQL, - ActionPlanId: AP_ID, - ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, - } - maps := APItoModelActionPlan(ap) - if err := mysqlDb.SetTpActionPlans(maps); err != nil { - t.Error(err.Error()) - } - if rAP, err := mysqlDb.GetTpActionPlans(utils.TEST_SQL, AP_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(maps[0], rAP[0]) { - t.Errorf("Expecting: %+v, received: %+v", maps, rAP) - } -} - -func TestMySQLSetGetTPActionTriggers(t *testing.T) { - if !*testLocal { - return - } - atrg := &utils.TPActionTrigger{ - Id: "MY_FIRST_ATGR", - BalanceType: "*monetary", - BalanceDirections: "*out", - ThresholdType: "*min_balance", - ThresholdValue: 2.0, - Recurrent: true, - BalanceDestinationIds: "*any", - Weight: 10.0, - ActionsId: "LOG_BALANCE", - } - atrgs := &utils.TPActionTriggers{ - TPid: utils.TEST_SQL, - ActionTriggersId: "MY_FIRST_ATGR", - ActionTriggers: []*utils.TPActionTrigger{atrg}, - } - matrg := APItoModelActionTrigger(atrgs) - if err := mysqlDb.SetTpActionTriggers(matrg); err != nil { - t.Error("Unexpected error: ", err.Error()) - } - if rcvMpAtrgs, err := mysqlDb.GetTpActionTriggers(utils.TEST_SQL, "MY_FIRST_ATGR"); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if !modelEqual(matrg[0], rcvMpAtrgs[0]) { - t.Errorf("Expecting: %v, received: %v", matrg, rcvMpAtrgs) - } -} - -func TestMySQLSetGetTpAccountActions(t *testing.T) { - if !*testLocal { - return - } - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", - ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := mysqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mysqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if !modelEqual(*maa, aas[0]) { - t.Errorf("Expecting: %+v, received: %+v", maa, aas) - } -} - -func TestMySQLGetTPIds(t *testing.T) { - if !*testLocal { - return - } - eTPIds := []string{utils.TEST_SQL} - if tpIds, err := mysqlDb.GetTpIds(); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(eTPIds, tpIds) { - t.Errorf("Expecting: %+v, received: %+v", eTPIds, tpIds) - } -} - -func TestMySQLRemoveTPData(t *testing.T) { - if !*testLocal { - return - } - // Create Timings - tm := &utils.ApierTPTiming{TPid: utils.TEST_SQL, TimingId: "ALWAYS", Time: "00:00:00"} - tms := APItoModelTiming(tm) - if err := mysqlDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Remove Timings - if err := mysqlDb.RemTpData(utils.TBL_TP_TIMINGS, utils.TEST_SQL, map[string]string{"tag": tm.TimingId}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tmgs) != 0 { - t.Errorf("Timings should be empty, got instead: %+v", tmgs) - } - // Create RatingProfile - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - mrp := APItoModelRatingProfile(rp) - if err := mysqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mysqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Remove RatingProfile - if err := mysqlDb.RemTpData(utils.TBL_TP_RATE_PROFILES, rp.TPid, map[string]string{"loadid": rp.LoadId, "direction": rp.Direction, "tenant": rp.Tenant, "category": rp.Category, "subject": rp.Subject}); err != nil { - t.Error(err.Error()) - } - if rps, err := mysqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rps) != 0 { - t.Errorf("RatingProfiles different than 0: %+v", rps) - } - // Create AccountActions - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", - ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := mysqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mysqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove AccountActions - if err := mysqlDb.RemTpData(utils.TBL_TP_ACCOUNT_ACTIONS, aa.TPid, map[string]string{"loadid": aa.LoadId, "tenant": aa.Tenant, "account": aa.Account}); err != nil { - t.Error(err.Error()) - } - if aas, err := mysqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } - // Create again so we can test complete TP removal - if err := mysqlDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Create RatingProfile - if err := mysqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := mysqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Create AccountActions - if err := mysqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := mysqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove TariffPlan completely - if err := mysqlDb.RemTpData("", utils.TEST_SQL, nil); err != nil { - t.Error(err.Error()) - } - // Make sure we have removed it - if tms, err := mysqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tms) != 0 { - t.Errorf("Non empty timings: %+v", tms) - } - if rpfs, err := mysqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rpfs) != 0 { - t.Errorf("Non empty rpfs: %+v", rpfs) - } - if aas, err := mysqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } -} - -func TestMySQLSetCdr(t *testing.T) { - if !*testLocal { - return - } - cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: utils.TEST_SQL} - - cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} { - if err := mysqlDb.SetCdr(cdr.AsStoredCdr("")); err != nil { - t.Error(err.Error()) - } - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mysqlDb.SetCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestMySQLSetRatedCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: "wholesale_run", Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mysqlDb.SetRatedCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestMySQLCallCost(t *testing.T) { - if !*testLocal { - return - } - cgrId := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cc := &CallCost{ - Direction: "*out", - Category: "call", - Tenant: "cgrates.org", - Subject: "91001", - Account: "8001", - Destination: "1002", - TOR: utils.VOICE, - Timespans: []*TimeSpan{ - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 40, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - }, - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 30, 0, time.UTC), - }, - }, - } - if err := mysqlDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := mysqlDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(cc, ccRcv) { - t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) - } - // UPDATE test here - cc.Category = "premium_call" - if err := mysqlDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := mysqlDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(cc, ccRcv) { - t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) - } -} - -func TestMySQLGetStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - var timeStart, timeEnd time.Time - // All CDRs, no filter - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count ALL - if storedCdrs, count, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Count: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } else if count != 8 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Limit 5 - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Offset 5 - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Offset with limit 2 - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(2), Offset: utils.IntPointer(5)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on cgrids - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count on CGRIDS - if _, count, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 2 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on cgrids plus reqType - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count on multiple filter - if _, count, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 1 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on runId - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{RunIds: []string{utils.DEFAULT_RUNID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on TOR - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple TOR - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS, utils.VOICE}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on cdrHost - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple cdrHost - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.1", "192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on cdrSource - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple cdrSource - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN", "UNKNOWN2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on reqType - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple reqType - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID, utils.META_PSEUDOPREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on direction - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Directions: []string{"*out"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on tenant - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple tenants - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com", "cgrates.org"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on category - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple categories - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call", "call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on account - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple account - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1001", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on subject - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple subject - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on destPrefix - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple destPrefixes - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"1001", "+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ratedAccount - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{RatedAccounts: []string{"8001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ratedSubject - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{RatedSubjects: []string{"91001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ignoreRated - var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } else { - for _, cdr := range storedCdrs { - if cdr.OrderId < orderIdStart { - orderIdStart = cdr.OrderId - } - if cdr.OrderId > orderIdEnd { - orderIdEnd = cdr.OrderId - } - } - } - // Filter on orderIdStart - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on orderIdStart and orderIdEnd - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart, OrderIdEnd: orderIdEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on timeStart - timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on timeStart and timeEnd - timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on minPdd - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on maxPdd - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxPdd: utils.Float64Pointer(3)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on minPdd, maxPdd - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3), MaxPdd: utils.Float64Pointer(5)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Combined filter - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ignoreDerived - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { // ToDo: Recheck this value - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } -} - -func TestMySQLRemStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - cgrIdB1 := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mysqlDb.RemStoredCdrs([]string{cgrIdB1}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - tm, _ := utils.ParseTimeDetectLayout("2013-11-08T08:42:20Z", "") - cgrIdA1 := utils.Sha1("aaa1", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-08T08:42:22Z", "") - cgrIdA2 := utils.Sha1("aaa2", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:24Z", "") - cgrIdA3 := utils.Sha1("aaa3", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:21Z", "") - cgrIdA4 := utils.Sha1("aaa4", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:25Z", "") - cgrIdA5 := utils.Sha1("aaa5", tm.String()) - cgrIdB2 := utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cgrIdB3 := utils.Sha1("bbb3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mysqlDb.RemStoredCdrs([]string{cgrIdA1, cgrIdA2, cgrIdA3, cgrIdA4, cgrIdA5, - cgrIdB2, cgrIdB3}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := mysqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } -} - -// Make sure that what we get is what we set -func TestMySQLStoreRestoreCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr := &StoredCdr{TOR: utils.VOICE, AccId: "ccc1", CdrHost: "192.168.1.1", CdrSource: "TEST_CDR", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr.CgrId = utils.Sha1(strCdr.AccId, strCdr.SetupTime.String()) - if err := mysqlDb.SetCdr(strCdr); err != nil { - t.Error(err.Error()) - } - if err := mysqlDb.SetRatedCdr(strCdr); err != nil { - t.Error(err.Error()) - } - // Check RawCdr - if rcvCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - !strCdr.SetupTime.Equal(rcvCdr.SetupTime) || - !strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } - // Check RatedCdr - if rcvCdrs, _, err := mysqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - //!strCdr.SetupTime.Equal(rcvCdr.SetupTime) || // FixMe - //!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || // FixMe - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - strCdr.Cost != rcvCdr.Cost || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } -} diff --git a/engine/storage_postgres.go b/engine/storage_postgres.go index 8641e828b..00862cd39 100644 --- a/engine/storage_postgres.go +++ b/engine/storage_postgres.go @@ -19,12 +19,7 @@ along with this program. If not, see package engine import ( - "encoding/json" "fmt" - "path" - "time" - - "github.com/cgrates/cgrates/utils" "github.com/jinzhu/gorm" _ "github.com/lib/pq" @@ -50,97 +45,3 @@ func NewPostgresStorage(host, port, name, user, password string, maxConn, maxIdl return &PostgresStorage{&SQLStorage{Db: db.DB(), db: db}}, nil } - -func (self *PostgresStorage) Flush(scriptsPath string) (err error) { - for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} { - if err := self.CreateTablesFromScript(path.Join(scriptsPath, scriptName)); err != nil { - return err - } - } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := self.Db.Query(fmt.Sprintf("SELECT 1 FROM %s", tbl)); err != nil { - return err - } - } - return nil -} - -func (self *PostgresStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) (err error) { - if cc == nil { - return nil - } - tss, err := json.Marshal(cc.Timespans) - if err != nil { - utils.Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err)) - return err - } - tx := self.db.Begin() - cd := &TblCostDetail{ - Cgrid: cgrid, - Runid: runid, - Tor: cc.TOR, - Direction: cc.Direction, - Tenant: cc.Tenant, - Category: cc.Category, - Account: cc.Account, - Subject: cc.Subject, - Destination: cc.Destination, - Cost: cc.Cost, - Timespans: string(tss), - CostSource: source, - 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) - tx.Rollback() - tx = self.db.Begin() - updated := tx.Model(TblCostDetail{}).Where(&TblCostDetail{Cgrid: cgrid, Runid: runid}).Updates(&TblCostDetail{Tor: cc.TOR, Direction: cc.Direction, Tenant: cc.Tenant, Category: cc.Category, - Account: cc.Account, Subject: cc.Subject, Destination: cc.Destination, Cost: cc.Cost, Timespans: string(tss), CostSource: source, UpdatedAt: time.Now()}) - if updated.Error != nil { - tx.Rollback() - return updated.Error - } - } - tx.Commit() - return nil -} - -func (self *PostgresStorage) SetRatedCdr(cdr *StoredCdr) (err error) { - tx := self.db.Begin() - saved := tx.Save(&TblRatedCdr{ - Cgrid: cdr.CgrId, - Runid: cdr.MediationRunId, - Reqtype: cdr.ReqType, - Direction: cdr.Direction, - Tenant: cdr.Tenant, - Category: cdr.Category, - Account: cdr.Account, - Subject: cdr.Subject, - Destination: cdr.Destination, - SetupTime: cdr.SetupTime, - AnswerTime: cdr.AnswerTime, - Usage: cdr.Usage.Seconds(), - Pdd: cdr.Pdd.Seconds(), - Supplier: cdr.Supplier, - DisconnectCause: cdr.DisconnectCause, - Cost: cdr.Cost, - ExtraInfo: cdr.ExtraInfo, - CreatedAt: time.Now(), - }) - if saved.Error != nil { - tx.Rollback() - tx = self.db.Begin() - updated := tx.Model(TblRatedCdr{}).Where(&TblRatedCdr{Cgrid: cdr.CgrId, Runid: cdr.MediationRunId}).Updates(&TblRatedCdr{Reqtype: cdr.ReqType, - Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination, - SetupTime: cdr.SetupTime, AnswerTime: cdr.AnswerTime, Usage: cdr.Usage.Seconds(), Pdd: cdr.Pdd.Seconds(), Supplier: cdr.Supplier, DisconnectCause: cdr.DisconnectCause, - Cost: cdr.Cost, ExtraInfo: cdr.ExtraInfo, - UpdatedAt: time.Now()}) - if updated.Error != nil { - tx.Rollback() - return updated.Error - } - } - tx.Commit() - return nil - -} diff --git a/engine/storage_psql_local_test.go b/engine/storage_psql_local_test.go deleted file mode 100644 index d3245c93f..000000000 --- a/engine/storage_psql_local_test.go +++ /dev/null @@ -1,985 +0,0 @@ -/* -Rating system designed to be used in VoIP Carriers World -Copyright (C) 2012-2015 ITsysCOM - -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 ( - "fmt" - "path" - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" -) - -var psqlDb *PostgresStorage - -func TestPSQLCreateTables(t *testing.T) { - if !*testLocal { - return - } - cgrConfig, _ := config.NewDefaultCGRConfig() - var err error - if psqlDb, err = NewPostgresStorage("localhost", "5432", cgrConfig.StorDBName, cgrConfig.StorDBUser, cgrConfig.StorDBPass, - cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns); err != nil { - t.Error("Error on opening database connection: ", err) - return - } - for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} { - if err := psqlDb.CreateTablesFromScript(path.Join(*dataDir, "storage", utils.POSTGRES, scriptName)); err != nil { - t.Error("Error on psqlDb creation: ", err.Error()) - return // No point in going further - } - } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := psqlDb.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { - t.Error(err.Error()) - } - } -} - -func TestPSQLSetGetTPTiming(t *testing.T) { - if !*testLocal { - return - } - tm := &utils.ApierTPTiming{TPid: utils.TEST_SQL, TimingId: "ALWAYS", Time: "00:00:00"} - mtm := APItoModelTiming(tm) - mtms := []TpTiming{*mtm} - if err := psqlDb.SetTpTimings(mtms); err != nil { - t.Error(err.Error()) - } - if tmgs, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mtms[0], tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mtms, tmgs) - } - // Update - tm.Time = "00:00:01" - if err := psqlDb.SetTpTimings(mtms); err != nil { - t.Error(err.Error()) - } - if tmgs, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mtms[0], tmgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mtms, tmgs) - } -} - -func TestPSQLSetGetTPDestination(t *testing.T) { - if !*testLocal { - return - } - dst := &utils.TPDestination{TPid: utils.TEST_SQL, DestinationId: utils.TEST_SQL, Prefixes: []string{"+49", "+49151", "+49176"}} - dests := APItoModelDestination(dst) - if err := psqlDb.SetTpDestinations(dests); err != nil { - t.Error(err.Error()) - } - storData, err := psqlDb.GetTpDestinations(utils.TEST_SQL, utils.TEST_SQL) - dsts, err := TpDestinations(storData).GetDestinations() - if err != nil { - t.Error(err.Error()) - } else if len(dst.Prefixes) != len(dsts[utils.TEST_SQL].Prefixes) { - t.Errorf("Expecting: %+v, received: %+v", dst, dsts[utils.TEST_SQL]) - } -} - -func TestPSQLSetGetTPRates(t *testing.T) { - if !*testLocal { - return - } - RT_ID := "RT_1" - rtSlots := []*utils.RateSlot{ - &utils.RateSlot{ConnectFee: 0.02, Rate: 0.01, RateUnit: "60s", RateIncrement: "60s", GroupIntervalStart: "0s"}, - &utils.RateSlot{ConnectFee: 0.00, Rate: 0.005, RateUnit: "60s", RateIncrement: "1s", GroupIntervalStart: "60s"}, - } - for _, rs := range rtSlots { - rs.SetDurations() - } - expectedTPRate := &utils.TPRate{TPid: utils.TEST_SQL, RateId: RT_ID, RateSlots: rtSlots} - mRates := APItoModelRate(expectedTPRate) - if err := psqlDb.SetTpRates(mRates); err != nil { - t.Error(err.Error()) - } - rts, err := psqlDb.GetTpRates(utils.TEST_SQL, RT_ID) - trts, err := TpRates(rts).GetRates() - if err != nil { - t.Error(err.Error()) - } else if len(expectedTPRate.RateSlots) != len(trts[RT_ID].RateSlots) { - t.Errorf("Expecting: %+v, received: %+v", expectedTPRate, trts[RT_ID]) - } -} - -func TestPSQLSetGetTPDestinationRates(t *testing.T) { - if !*testLocal { - return - } - DR_ID := "DR_1" - dr := &utils.DestinationRate{DestinationId: "DST_1", RateId: "RT_1", RoundingMethod: "*up", RoundingDecimals: 4} - eDrs := &utils.TPDestinationRate{TPid: utils.TEST_SQL, DestinationRateId: DR_ID, DestinationRates: []*utils.DestinationRate{dr}} - mdrs := APItoModelDestinationRate(eDrs) - if err := psqlDb.SetTpDestinationRates(mdrs); err != nil { - t.Error(err.Error()) - } - if drs, err := psqlDb.GetTpDestinationRates(utils.TEST_SQL, DR_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdrs[0], drs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdrs, drs) - } -} - -func TestPSQLSetGetTPRatingPlans(t *testing.T) { - if !*testLocal { - return - } - RP_ID := "RP_1" - rbBinding := &utils.TPRatingPlanBinding{DestinationRatesId: "DR_1", TimingId: "TM_1", Weight: 10.0} - rp := &utils.TPRatingPlan{ - TPid: utils.TEST_SQL, - RatingPlanId: RP_ID, - RatingPlanBindings: []*utils.TPRatingPlanBinding{rbBinding}, - } - mrp := APItoModelRatingPlan(rp) - - if err := psqlDb.SetTpRatingPlans(mrp); err != nil { - t.Error(err.Error()) - } - if drps, err := psqlDb.GetTpRatingPlans(utils.TEST_SQL, RP_ID, nil); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], drps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, drps) - } -} - -func TestPSQLSetGetTPRatingProfiles(t *testing.T) { - if !*testLocal { - return - } - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RP_1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - - mrp := APItoModelRatingProfile(rp) - if err := psqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := psqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mrp[0], rps[0]) { - t.Errorf("Expecting: %+v, received: %+v", mrp, rps) - } -} - -func TestPSQLSetGetTPSharedGroups(t *testing.T) { - if !*testLocal { - return - } - SG_ID := "SG_1" - tpSgs := &utils.TPSharedGroups{ - TPid: utils.TEST_SQL, - SharedGroupsId: SG_ID, - SharedGroups: []*utils.TPSharedGroup{ - &utils.TPSharedGroup{Account: "dan", Strategy: "*lowest_first", RatingSubject: "lowest_rates"}, - }, - } - mSgs := APItoModelSharedGroup(tpSgs) - if err := psqlDb.SetTpSharedGroups(mSgs); err != nil { - t.Error(err.Error()) - } - if sgs, err := psqlDb.GetTpSharedGroups(utils.TEST_SQL, SG_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mSgs[0], sgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mSgs, sgs) - } -} - -func TestPSQLSetGetTPCdrStats(t *testing.T) { - if !*testLocal { - return - } - CS_ID := "CDRSTATS_1" - setCS := &utils.TPCdrStats{ - TPid: utils.TEST_SQL, - CdrStatsId: CS_ID, - CdrStats: []*utils.TPCdrStat{ - &utils.TPCdrStat{QueueLength: "10", TimeWindow: "10m", Metrics: "ASR", Tenants: "cgrates.org", Categories: "call"}, - }, - } - mcs := APItoModelCdrStat(setCS) - if err := psqlDb.SetTpCdrStats(mcs); err != nil { - t.Error(err.Error()) - } - if cs, err := psqlDb.GetTpCdrStats(utils.TEST_SQL, CS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mcs[0], cs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mcs, cs) - } -} - -func TestPSQLSetGetTPDerivedChargers(t *testing.T) { - if !*testLocal { - return - } - dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", - UsageField: "cgr_duration", SupplierField: "^supplier1"} - dcs := &utils.TPDerivedChargers{TPid: utils.TEST_SQL, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: []*utils.TPDerivedCharger{dc}} - mdcs := APItoModelDerivedCharger(dcs) - if err := psqlDb.SetTpDerivedChargers(mdcs); err != nil { - t.Error(err.Error()) - } - if rDCs, err := psqlDb.GetTpDerivedChargers(&mdcs[0]); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mdcs[0], rDCs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mdcs, rDCs) - } -} - -func TestPSQLSetGetTPActions(t *testing.T) { - if !*testLocal { - return - } - ACTS_ID := "PREPAID_10" - acts := []*utils.TPAction{ - &utils.TPAction{Identifier: "*topup_reset", BalanceType: "*monetary", Directions: "*out", Units: 10, ExpiryTime: "*unlimited", - DestinationIds: "*any", BalanceWeight: 10, Weight: 10}} - tpActions := &utils.TPActions{TPid: utils.TEST_SQL, ActionsId: ACTS_ID, Actions: acts} - mas := APItoModelAction(tpActions) - if err := psqlDb.SetTpActions(mas); err != nil { - t.Error(err.Error()) - } - if rTpActs, err := psqlDb.GetTpActions(utils.TEST_SQL, ACTS_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(mas[0], rTpActs[0]) { - t.Errorf("Expecting: %+v, received: %+v", mas, rTpActs) - } -} - -func TestPSQLTPActionTimings(t *testing.T) { - if !*testLocal { - return - } - AP_ID := "AP_1" - ap := &utils.TPActionPlan{ - TPid: utils.TEST_SQL, - ActionPlanId: AP_ID, - ActionPlan: []*utils.TPActionTiming{&utils.TPActionTiming{ActionsId: "ACTS_1", TimingId: "TM_1", Weight: 10.0}}, - } - maps := APItoModelActionPlan(ap) - if err := psqlDb.SetTpActionPlans(maps); err != nil { - t.Error(err.Error()) - } - if rAP, err := psqlDb.GetTpActionPlans(utils.TEST_SQL, AP_ID); err != nil { - t.Error(err.Error()) - } else if !modelEqual(maps[0], rAP[0]) { - t.Errorf("Expecting: %+v, received: %+v", maps, rAP) - } -} - -func TestPSQLSetGetTPActionTriggers(t *testing.T) { - if !*testLocal { - return - } - atrg := &utils.TPActionTrigger{ - Id: "MY_FIRST_ATGR", - BalanceType: "*monetary", - BalanceDirections: "*out", - ThresholdType: "*min_balance", - ThresholdValue: 2.0, - Recurrent: true, - BalanceDestinationIds: "*any", - Weight: 10.0, - ActionsId: "LOG_BALANCE", - } - atrgs := &utils.TPActionTriggers{ - TPid: utils.TEST_SQL, - ActionTriggersId: "MY_FIRST_ATGR", - ActionTriggers: []*utils.TPActionTrigger{atrg}, - } - matrg := APItoModelActionTrigger(atrgs) - if err := psqlDb.SetTpActionTriggers(matrg); err != nil { - t.Error("Unexpected error: ", err.Error()) - } - if rcvMpAtrgs, err := psqlDb.GetTpActionTriggers(utils.TEST_SQL, "MY_FIRST_ATGR"); err != nil { - t.Error("Unexpected error: ", err.Error()) - } else if !modelEqual(matrg[0], rcvMpAtrgs[0]) { - t.Errorf("Expecting: %+v, received: %+v", matrg, rcvMpAtrgs) - } -} - -func TestPSQLSetGetTpAccountActions(t *testing.T) { - if !*testLocal { - return - } - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", - ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := psqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := psqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if !modelEqual(*maa, aas[0]) { - t.Errorf("Expecting: %+v, received: %+v", maa, aas) - } -} - -func TestPSQLGetTPIds(t *testing.T) { - if !*testLocal { - return - } - eTPIds := []string{utils.TEST_SQL} - if tpIds, err := psqlDb.GetTpIds(); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(eTPIds, tpIds) { - t.Errorf("Expecting: %+v, received: %+v", eTPIds, tpIds) - } -} - -func TestPSQLRemoveTPData(t *testing.T) { - if !*testLocal { - return - } - // Create Timings - tm := &utils.ApierTPTiming{TPid: utils.TEST_SQL, TimingId: "ALWAYS", Time: "00:00:00"} - tms := APItoModelTiming(tm) - if err := psqlDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Remove Timings - if err := psqlDb.RemTpData(utils.TBL_TP_TIMINGS, utils.TEST_SQL, map[string]string{"tag": tm.TimingId}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tmgs) != 0 { - t.Errorf("Timings should be empty, got instead: %+v", tmgs) - } - // Create RatingProfile - ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1"}} - rp := &utils.TPRatingProfile{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - mrp := APItoModelRatingProfile(rp) - if err := psqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := psqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Remove RatingProfile - if err := psqlDb.RemTpData(utils.TBL_TP_RATE_PROFILES, rp.TPid, map[string]string{"loadid": rp.LoadId, "direction": rp.Direction, "tenant": rp.Tenant, "category": rp.Category, "subject": rp.Subject}); err != nil { - t.Error(err.Error()) - } - if rps, err := psqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rps) != 0 { - t.Errorf("RatingProfiles different than 0: %+v", rps) - } - // Create AccountActions - aa := &utils.TPAccountActions{TPid: utils.TEST_SQL, LoadId: utils.TEST_SQL, Tenant: "cgrates.org", Account: "1001", - ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - maa := APItoModelAccountAction(aa) - if err := psqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := psqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove AccountActions - if err := psqlDb.RemTpData(utils.TBL_TP_ACCOUNT_ACTIONS, aa.TPid, map[string]string{"loadid": aa.LoadId, "tenant": aa.Tenant, "account": aa.Account}); err != nil { - t.Error(err.Error()) - } - if aas, err := psqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } - // Create again so we can test complete TP removal - if err := psqlDb.SetTpTimings([]TpTiming{*tms}); err != nil { - t.Error(err.Error()) - } - if tmgs, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err.Error()) - } else if len(tmgs) == 0 { - t.Error("Could not store TPTiming") - } - // Create RatingProfile - if err := psqlDb.SetTpRatingProfiles(mrp); err != nil { - t.Error(err.Error()) - } - if rps, err := psqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err.Error()) - } else if len(rps) == 0 { - t.Error("Could not store TPRatingProfile") - } - // Create AccountActions - if err := psqlDb.SetTpAccountActions([]TpAccountAction{*maa}); err != nil { - t.Error(err.Error()) - } - if aas, err := psqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err.Error()) - } else if len(aas) == 0 { - t.Error("Could not create TPAccountActions") - } - // Remove TariffPlan completely - if err := psqlDb.RemTpData("", utils.TEST_SQL, nil); err != nil { - t.Error(err.Error()) - } - // Make sure we have removed it - if tms, err := psqlDb.GetTpTimings(utils.TEST_SQL, tm.TimingId); err != nil { - t.Error(err) - } else if len(tms) != 0 { - t.Errorf("Non empty timings: %+v", tms) - } - if rpfs, err := psqlDb.GetTpRatingProfiles(&mrp[0]); err != nil { - t.Error(err) - } else if len(rpfs) != 0 { - t.Errorf("Non empty rpfs: %+v", rpfs) - } - if aas, err := psqlDb.GetTpAccountActions(maa); err != nil { - t.Error(err) - } else if len(aas) != 0 { - t.Errorf("Non empty account actions: %+v", aas) - } -} - -func TestPSQLSetCdr(t *testing.T) { - if !*testLocal { - return - } - cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: utils.TEST_SQL} - - cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z", - utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org", - utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", utils.PDD: "4s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com", - utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z", - utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", utils.PDD: "7s", utils.SUPPLIER: "SUPPL1", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": utils.TEST_SQL} - - for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} { - if err := psqlDb.SetCdr(cdr.AsStoredCdr("")); err != nil { - t.Error(err.Error()) - } - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(4) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := psqlDb.SetCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestPSQLCallCost(t *testing.T) { - if !*testLocal { - return - } - cgrId := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cc := &CallCost{ - Direction: "*out", - Category: "call", - Tenant: "cgrates.org", - Subject: "91001", - Account: "8001", - Destination: "1002", - TOR: utils.VOICE, - Timespans: []*TimeSpan{ - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 40, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - }, - &TimeSpan{ - TimeStart: time.Date(2013, 9, 10, 13, 41, 0, 0, time.UTC), - TimeEnd: time.Date(2013, 9, 10, 13, 41, 30, 0, time.UTC), - }, - }, - } - if err := psqlDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := psqlDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(cc, ccRcv) { - t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) - } - // UPDATE test here - cc.Category = "premium_call" - if err := psqlDb.LogCallCost(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID, cc); err != nil { - t.Error(err.Error()) - } - if ccRcv, err := psqlDb.GetCallCostLog(cgrId, utils.TEST_SQL, utils.DEFAULT_RUNID); err != nil { - t.Error(err.Error()) - } else if !reflect.DeepEqual(cc, ccRcv) { - t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) - } -} - -func TestPSQLSetRatedCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String()) - strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID, - Direction: "*out", 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(12) * time.Second, Pdd: time.Duration(7) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201} - strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String()) - strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: utils.TEST_SQL, ReqType: utils.META_RATED, - Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964", - 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, Pdd: time.Duration(2) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: "wholesale_run", Cost: 1.201} - strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) - - for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := psqlDb.SetRatedCdr(cdr); err != nil { - t.Error(err.Error()) - } - } -} - -func TestPSQLGetStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - var timeStart, timeEnd time.Time - // All CDRs, no filter - if storedCdrs, _, err := psqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count ALL - if storedCdrs, count, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Count: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } else if count != 8 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Limit 5 - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Offset 5 - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(5), Offset: utils.IntPointer(0)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Offset with limit 2 - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Paginator: utils.Paginator{Limit: utils.IntPointer(2), Offset: utils.IntPointer(5)}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", len(storedCdrs)) - } - // Filter on cgrids - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count on CGRIDS - if _, count, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 2 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on cgrids plus reqType - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Count on multiple filter - if _, count, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, ReqTypes: []string{utils.META_PREPAID}, Count: true}); err != nil { - t.Error(err.Error()) - } else if count != 1 { - t.Error("Unexpected count of StoredCdrs returned: ", count) - } - // Filter on runId - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{RunIds: []string{utils.DEFAULT_RUNID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on TOR - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple TOR - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Tors: []string{utils.SMS, utils.VOICE}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on cdrHost - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple cdrHost - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrHosts: []string{"192.168.1.1", "192.168.1.2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on cdrSource - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple cdrSource - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CdrSources: []string{"UNKNOWN", "UNKNOWN2"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on reqType - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple reqType - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_PREPAID, utils.META_PSEUDOPREPAID}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on direction - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Directions: []string{"*out"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on tenant - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple tenants - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Tenants: []string{"itsyscom.com", "cgrates.org"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on category - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple categories - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Categories: []string{"premium_call", "call"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on account - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple account - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Accounts: []string{"1001", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on subject - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple subject - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{Subjects: []string{"1000", "1002"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on destPrefix - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 3 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on multiple destPrefixes - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{DestPrefixes: []string{"1001", "+498651"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ratedAccount - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{RatedAccounts: []string{"8001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ratedSubject - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{RatedSubjects: []string{"91001"}}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ignoreRated - var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxCost: utils.Float64Pointer(0.0)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } else { - for _, cdr := range storedCdrs { - if cdr.OrderId < orderIdStart { - orderIdStart = cdr.OrderId - } - if cdr.OrderId > orderIdEnd { - orderIdEnd = cdr.OrderId - } - } - } - // Filter on orderIdStart - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 8 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on orderIdStart and orderIdEnd - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{OrderIdStart: orderIdStart, OrderIdEnd: orderIdEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 4 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on timeStart - timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on timeStart and timeEnd - timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC) - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 2 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on minPdd - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on maxPdd - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MaxPdd: utils.Float64Pointer(3)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on minPdd, maxPdd - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{MinPdd: utils.Float64Pointer(3), MaxPdd: utils.Float64Pointer(5)}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 5 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Combined filter - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{ReqTypes: []string{utils.META_RATED}, AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 1 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - // Filter on ignoreDerived - if storedCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{AnswerTimeStart: &timeStart, AnswerTimeEnd: &timeEnd, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { // ToDo: Recheck this value - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } -} - -func TestPSQLRemStoredCdrs(t *testing.T) { - if !*testLocal { - return - } - cgrIdB1 := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := psqlDb.RemStoredCdrs([]string{cgrIdB1}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := psqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 7 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } - tm, _ := utils.ParseTimeDetectLayout("2013-11-08T08:42:20Z", "") - cgrIdA1 := utils.Sha1("aaa1", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-08T08:42:22Z", "") - cgrIdA2 := utils.Sha1("aaa2", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:24Z", "") - cgrIdA3 := utils.Sha1("aaa3", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:21Z", "") - cgrIdA4 := utils.Sha1("aaa4", tm.String()) - tm, _ = utils.ParseTimeDetectLayout("2013-11-07T08:42:25Z", "") - cgrIdA5 := utils.Sha1("aaa5", tm.String()) - cgrIdB2 := utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - cgrIdB3 := utils.Sha1("bbb3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := psqlDb.RemStoredCdrs([]string{cgrIdA1, cgrIdA2, cgrIdA3, cgrIdA4, cgrIdA5, - cgrIdB2, cgrIdB3}); err != nil { - t.Error(err.Error()) - } - if storedCdrs, _, err := psqlDb.GetStoredCdrs(new(utils.CdrsFilter)); err != nil { - t.Error(err.Error()) - } else if len(storedCdrs) != 0 { - t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) - } -} - -// Make sure that what we get is what we set -func TestPSQLStoreRestoreCdr(t *testing.T) { - if !*testLocal { - return - } - strCdr := &StoredCdr{TOR: utils.VOICE, AccId: "ccc1", CdrHost: "192.168.1.1", CdrSource: "TEST_CDR", ReqType: utils.META_RATED, - Direction: "*out", 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, Pdd: time.Duration(3) * time.Second, Supplier: "SUPPL1", - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201} - strCdr.CgrId = utils.Sha1(strCdr.AccId, strCdr.SetupTime.String()) - if err := psqlDb.SetCdr(strCdr); err != nil { - t.Error(err.Error()) - } - if err := psqlDb.SetRatedCdr(strCdr); err != nil { - t.Error(err.Error()) - } - // Check RawCdr - if rcvCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - !strCdr.SetupTime.Equal(rcvCdr.SetupTime) || - !strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } - // Check RatedCdr - if rcvCdrs, _, err := psqlDb.GetStoredCdrs(&utils.CdrsFilter{CgrIds: []string{strCdr.CgrId}, FilterOnRated: true}); err != nil { - t.Error(err.Error()) - } else if len(rcvCdrs) != 1 { - t.Errorf("Unexpected cdrs returned: %+v", rcvCdrs) - } else { - rcvCdr := rcvCdrs[0] - if strCdr.CgrId != rcvCdr.CgrId || - strCdr.TOR != rcvCdr.TOR || - strCdr.AccId != rcvCdr.AccId || - strCdr.CdrHost != rcvCdr.CdrHost || - strCdr.ReqType != rcvCdr.ReqType || - strCdr.Direction != rcvCdr.Direction || - strCdr.Tenant != rcvCdr.Tenant || - strCdr.Category != rcvCdr.Category || - strCdr.Account != rcvCdr.Account || - strCdr.Subject != rcvCdr.Subject || - strCdr.Destination != rcvCdr.Destination || - //!strCdr.SetupTime.Equal(rcvCdr.SetupTime) || // FixMe - //!strCdr.AnswerTime.Equal(rcvCdr.AnswerTime) || // FixMe - strCdr.Usage != rcvCdr.Usage || - strCdr.Pdd != rcvCdr.Pdd || - strCdr.Supplier != rcvCdr.Supplier || - strCdr.DisconnectCause != rcvCdr.DisconnectCause || - strCdr.Cost != rcvCdr.Cost || - !reflect.DeepEqual(strCdr.ExtraFields, rcvCdr.ExtraFields) { - t.Errorf("Expecting: %+v, received: %+v", strCdr, rcvCdrs[0]) - } - } -} diff --git a/engine/storage_redis_local_test.go b/engine/storage_redis_local_test.go index b4c43b05e..d07d46b85 100644 --- a/engine/storage_redis_local_test.go +++ b/engine/storage_redis_local_test.go @@ -57,9 +57,9 @@ func TestSetGetDerivedCharges(t *testing.T) { } keyCharger1 := utils.ConcatenatedKey("*out", "cgrates.org", "call", "dan", "dan") charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ - &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra1", RequestTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + &utils.DerivedCharger{RunID: "extra2", RequestTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, }} if err := rds.SetDerivedChargers(keyCharger1, charger1); err != nil { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 2c0336e90..935a3eb8c 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -24,12 +24,12 @@ import ( "encoding/json" "fmt" "io/ioutil" + "path" "strconv" "strings" "time" "github.com/cgrates/cgrates/utils" - "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) @@ -43,8 +43,16 @@ func (self *SQLStorage) Close() { self.db.Close() } -func (self *SQLStorage) Flush(placeholder string) (err error) { - return utils.ErrNotImplemented +func (self *SQLStorage) Flush(scriptsPath string) (err error) { + for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} { + if err := self.CreateTablesFromScript(path.Join(scriptsPath, scriptName)); err != nil { + return err + } + } + if _, err := self.Db.Query(fmt.Sprintf("SELECT 1 FROM %s", utils.TBL_CDRS)); err != nil { + return err + } + return nil } func (self *SQLStorage) GetKeysForPrefix(prefix string) ([]string, error) { @@ -561,32 +569,44 @@ func (self *SQLStorage) SetTpAccountActions(aas []TpAccountAction) error { return nil } - -func (self *SQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost) error { - return utils.ErrNotImplemented +func (self *SQLStorage) LogCallCost(cgrid, runid, source string, cc *CallCost) error { + if cc == nil { + return nil + } + tss, err := json.Marshal(cc) + if err != nil { + utils.Logger.Err(fmt.Sprintf("Error marshalling timespans to json: %v", err)) + return err + } + tx := self.db.Begin() + cd := &TBLSMCosts{ + Cgrid: cgrid, + RunID: runid, + CostSource: source, + CostDetails: string(tss), + 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) + tx.Rollback() + return tx.Error + } + tx.Commit() + return nil } -func (self *SQLStorage) GetCallCostLog(cgrid, source, runid string) (*CallCost, error) { - var tpCostDetail TblCostDetail - if err := self.db.Where(&TblCostDetail{Cgrid: cgrid, Runid: runid, CostSource: source}).First(&tpCostDetail).Error; err != nil { +func (self *SQLStorage) GetCallCostLog(cgrid, runid string) (*CallCost, error) { + var tpCostDetail TBLSMCosts + if err := self.db.Where(&TBLSMCosts{Cgrid: cgrid, RunID: runid}).First(&tpCostDetail).Error; err != nil { return nil, err } - if len(tpCostDetail.Timespans) == 0 { + if len(tpCostDetail.CostDetails) == 0 { return nil, nil // No costs returned } - cc := new(CallCost) - cc.TOR = tpCostDetail.Tor - cc.Direction = tpCostDetail.Direction - cc.Category = tpCostDetail.Category - cc.Tenant = tpCostDetail.Tenant - cc.Account = tpCostDetail.Account - cc.Subject = tpCostDetail.Subject - cc.Destination = tpCostDetail.Destination - cc.Cost = tpCostDetail.Cost - if err := json.Unmarshal([]byte(tpCostDetail.Timespans), &cc.Timespans); err != nil { + var cc CallCost + if err := json.Unmarshal([]byte(tpCostDetail.CostDetails), &cc); err != nil { return nil, err } - return cc, nil + return &cc, nil } func (self *SQLStorage) LogActionTrigger(ubId, source string, at *ActionTrigger, as Actions) (err error) { @@ -596,19 +616,20 @@ func (self *SQLStorage) LogActionTiming(source string, at *ActionTiming, as Acti return } -func (self *SQLStorage) SetCdr(cdr *StoredCdr) error { +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(&TblCdrsPrimary{ - Cgrid: cdr.CgrId, - Tor: cdr.TOR, - Accid: cdr.AccId, - Cdrhost: cdr.CdrHost, - Cdrsource: cdr.CdrSource, - Reqtype: cdr.ReqType, + 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, @@ -616,248 +637,176 @@ func (self *SQLStorage) SetCdr(cdr *StoredCdr) error { Subject: cdr.Subject, Destination: cdr.Destination, SetupTime: cdr.SetupTime, + Pdd: cdr.PDD.Seconds(), AnswerTime: cdr.AnswerTime, Usage: cdr.Usage.Seconds(), - Pdd: cdr.Pdd.Seconds(), Supplier: cdr.Supplier, DisconnectCause: cdr.DisconnectCause, - CreatedAt: time.Now()}) + ExtraFields: string(extraFields), + CostSource: cdr.CostSource, + Cost: cdr.Cost, + CostDetails: cdr.CostDetailsJson(), + ExtraInfo: cdr.ExtraInfo, + CreatedAt: time.Now(), + }) if saved.Error != nil { tx.Rollback() - return saved.Error - } - // Save extra fields - if err := tx.Save(&TblCdrsExtra{Cgrid: cdr.CgrId, ExtraFields: string(extraFields), CreatedAt: time.Now()}).Error; err != nil { - tx.Rollback() - return err + if !allowUpdate { + return saved.Error + } + tx = self.db.Begin() + updated := tx.Model(TBLCDRs{}).Where(&TBLCDRs{Cgrid: cdr.CGRID, RunID: cdr.RunID}).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(), + ExtraInfo: cdr.ExtraInfo, + UpdatedAt: time.Now(), + }, + ) + if updated.Error != nil { + tx.Rollback() + return updated.Error + } } tx.Commit() return nil } -func (self *SQLStorage) SetRatedCdr(storedCdr *StoredCdr) error { - return utils.ErrNotImplemented -} -func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, int64, error) { - var cdrs []*StoredCdr - // Select string - var selectStr string - if qryFltr.FilterOnRated { // We use different tables to query account data in case of derived - selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.pdd,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans", - utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, - utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, - utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, - utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS) - } else { - selectStr = fmt.Sprintf("%s.cgrid,%s.id,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.usage,%s.pdd,%s.supplier,%s.disconnect_cause,%s.extra_fields,%s.runid,%s.cost,%s.tor,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.cost,%s.timespans", - utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, - utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS, utils.TBL_COST_DETAILS) +func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter) ([]*CDR, int64, error) { + var cdrs []*CDR - } - // Join string - joinStr := fmt.Sprintf("LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid AND %s.runid=%s.runid", utils.TBL_CDRS_EXTRA, utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS, utils.TBL_RATED_CDRS, utils.TBL_COST_DETAILS) - q := self.db.Table(utils.TBL_CDRS_PRIMARY).Select(selectStr).Joins(joinStr) + q := self.db.Table(utils.TBL_CDRS).Select("*") if qryFltr.Unscoped { q = q.Unscoped() } else { // Query filter - for _, tblName := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_COST_DETAILS, utils.TBL_RATED_CDRS} { - q = q.Where(fmt.Sprintf("(%s.deleted_at IS NULL OR %s.deleted_at <= '0001-01-02')", tblName, tblName)) // Soft deletes - } + q = q.Where("(deleted_at IS NULL OR deleted_at <= '0001-01-02')") // Soft deletes } // Add filters, use in to replace the high number of ORs - if len(qryFltr.CgrIds) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cgrid in (?)", qryFltr.CgrIds) + if len(qryFltr.CGRIDs) != 0 { + q = q.Where("cgrid in (?)", qryFltr.CGRIDs) } - if len(qryFltr.NotCgrIds) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cgrid not in (?)", qryFltr.NotCgrIds) + if len(qryFltr.NotCGRIDs) != 0 { + q = q.Where("cgrid not in (?)", qryFltr.NotCGRIDs) } - if len(qryFltr.RunIds) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".runid in (?)", qryFltr.RunIds) + if len(qryFltr.RunIDs) != 0 { + q = q.Where("run_id in (?)", qryFltr.RunIDs) } - if len(qryFltr.NotRunIds) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".runid not in (?)", qryFltr.NotRunIds) + if len(qryFltr.NotRunIDs) != 0 { + q = q.Where("run_id not in (?)", qryFltr.NotRunIDs) } - if len(qryFltr.Tors) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".tor in (?)", qryFltr.Tors) + if len(qryFltr.ToRs) != 0 { + q = q.Where("tor in (?)", qryFltr.ToRs) } - if len(qryFltr.NotTors) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".tor not in (?)", qryFltr.NotTors) + if len(qryFltr.NotToRs) != 0 { + q = q.Where("tor not in (?)", qryFltr.NotToRs) } - if len(qryFltr.CdrHosts) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrhost in (?)", qryFltr.CdrHosts) + if len(qryFltr.OriginHosts) != 0 { + q = q.Where("origin_host in (?)", qryFltr.OriginHosts) } - if len(qryFltr.NotCdrHosts) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrhost not in (?)", qryFltr.NotCdrHosts) + if len(qryFltr.NotOriginHosts) != 0 { + q = q.Where("origin_host not in (?)", qryFltr.NotOriginHosts) } - if len(qryFltr.CdrSources) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrsource in (?)", qryFltr.CdrSources) + if len(qryFltr.Sources) != 0 { + q = q.Where("source in (?)", qryFltr.Sources) } - if len(qryFltr.NotCdrSources) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrsource not in (?)", qryFltr.NotCdrSources) + if len(qryFltr.NotSources) != 0 { + q = q.Where("source not in (?)", qryFltr.NotSources) } - if len(qryFltr.ReqTypes) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".reqtype in (?)", qryFltr.ReqTypes) + if len(qryFltr.RequestTypes) != 0 { + q = q.Where("request_type in (?)", qryFltr.RequestTypes) } - if len(qryFltr.NotReqTypes) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".reqtype not in (?)", qryFltr.NotReqTypes) + if len(qryFltr.NotRequestTypes) != 0 { + q = q.Where("request_type not in (?)", qryFltr.NotRequestTypes) } if len(qryFltr.Directions) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".direction in (?)", qryFltr.Directions) + q = q.Where("direction in (?)", qryFltr.Directions) } if len(qryFltr.NotDirections) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".direction not in (?)", qryFltr.NotDirections) + q = q.Where("direction not in (?)", qryFltr.NotDirections) } if len(qryFltr.Tenants) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".tenant in (?)", qryFltr.Tenants) + q = q.Where("tenant in (?)", qryFltr.Tenants) } if len(qryFltr.NotTenants) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".tenant not in (?)", qryFltr.NotTenants) + q = q.Where("tenant not in (?)", qryFltr.NotTenants) } if len(qryFltr.Categories) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".category in (?)", qryFltr.Categories) + q = q.Where("category in (?)", qryFltr.Categories) } if len(qryFltr.NotCategories) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".category not in (?)", qryFltr.NotCategories) + q = q.Where("category not in (?)", qryFltr.NotCategories) } if len(qryFltr.Accounts) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".account in (?)", qryFltr.Accounts) + q = q.Where("account in (?)", qryFltr.Accounts) } if len(qryFltr.NotAccounts) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".account not in (?)", qryFltr.NotAccounts) + q = q.Where("account not in (?)", qryFltr.NotAccounts) } if len(qryFltr.Subjects) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".subject in (?)", qryFltr.Subjects) + q = q.Where("subject in (?)", qryFltr.Subjects) } if len(qryFltr.NotSubjects) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".subject not in (?)", qryFltr.NotSubjects) + q = q.Where("subject not in (?)", qryFltr.NotSubjects) } - if len(qryFltr.DestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } + if len(qryFltr.DestinationPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm qIds := bytes.NewBufferString("(") - for idx, destPrefix := range qryFltr.DestPrefixes { + for idx, destPrefix := range qryFltr.DestinationPrefixes { if idx != 0 { qIds.WriteString(" OR") } - qIds.WriteString(fmt.Sprintf(" %s.destination LIKE '%s%%'", tblName, destPrefix)) + qIds.WriteString(fmt.Sprintf(" destination LIKE '%s%%'", destPrefix)) } qIds.WriteString(" )") q = q.Where(qIds.String()) } - if len(qryFltr.NotDestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } + if len(qryFltr.NotDestinationPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm qIds := bytes.NewBufferString("(") - for idx, destPrefix := range qryFltr.NotDestPrefixes { + for idx, destPrefix := range qryFltr.NotDestinationPrefixes { if idx != 0 { qIds.WriteString(" AND") } - qIds.WriteString(fmt.Sprintf(" %s.destination not LIKE '%%%s%%'", tblName, destPrefix)) + qIds.WriteString(fmt.Sprintf(" destination not LIKE '%s%%'", destPrefix)) } qIds.WriteString(" )") q = q.Where(qIds.String()) } if len(qryFltr.Suppliers) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".supplier in (?)", qryFltr.Subjects) + q = q.Where("supplier in (?)", qryFltr.Subjects) } if len(qryFltr.NotSuppliers) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".supplier not in (?)", qryFltr.NotSubjects) + q = q.Where("supplier not in (?)", qryFltr.NotSubjects) } if len(qryFltr.DisconnectCauses) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".disconnect_cause in (?)", qryFltr.DisconnectCauses) + q = q.Where("disconnect_cause in (?)", qryFltr.DisconnectCauses) } if len(qryFltr.NotDisconnectCauses) != 0 { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".disconnect_cause not in (?)", qryFltr.NotDisconnectCauses) - } - if len(qryFltr.RatedAccounts) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".account in (?)", qryFltr.RatedAccounts) - } - if len(qryFltr.NotRatedAccounts) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".account not in (?)", qryFltr.NotRatedAccounts) - } - if len(qryFltr.RatedSubjects) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".subject in (?)", qryFltr.RatedSubjects) - } - if len(qryFltr.NotRatedSubjects) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".subject not in (?)", qryFltr.NotRatedSubjects) + q = q.Where("disconnect_cause not in (?)", qryFltr.NotDisconnectCauses) } if len(qryFltr.Costs) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".cost in (?)", qryFltr.Costs) + q = q.Where(utils.TBL_CDRS+".cost in (?)", qryFltr.Costs) } if len(qryFltr.NotCosts) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".cost not in (?)", qryFltr.NotCosts) + q = q.Where(utils.TBL_CDRS+".cost not in (?)", qryFltr.NotCosts) } if len(qryFltr.ExtraFields) != 0 { // Extra fields searches, implemented as contains in extra field qIds := bytes.NewBufferString("(") @@ -866,7 +815,7 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, if needOr { qIds.WriteString(" OR") } - qIds.WriteString(fmt.Sprintf(` %s.extra_fields LIKE '%%"%s":"%s"%%'`, utils.TBL_CDRS_EXTRA, field, value)) + qIds.WriteString(fmt.Sprintf(` extra_fields LIKE '%%"%s":"%s"%%'`, field, value)) needOr = true } qIds.WriteString(" )") @@ -879,117 +828,87 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, if needAnd { qIds.WriteString(" OR") } - qIds.WriteString(fmt.Sprintf(` %s.extra_fields LIKE '%%"%s":"%s"%%'`, utils.TBL_CDRS_EXTRA, field, value)) + qIds.WriteString(fmt.Sprintf(` extra_fields LIKE '%%"%s":"%s"%%'`, field, value)) needAnd = true } qIds.WriteString(" )") q = q.Where(qIds.String()) } - if qryFltr.OrderIdStart != 0 { // Keep backwards compatible by testing 0 value - q = q.Where(utils.TBL_CDRS_PRIMARY+".id >= ?", qryFltr.OrderIdStart) + if qryFltr.OrderIDStart != nil { // Keep backwards compatible by testing 0 value + q = q.Where(utils.TBL_CDRS+".id >= ?", *qryFltr.OrderIDStart) } - if qryFltr.OrderIdEnd != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".id < ?", qryFltr.OrderIdEnd) + if qryFltr.OrderIDEnd != nil { + q = q.Where(utils.TBL_CDRS+".id < ?", *qryFltr.OrderIDEnd) } if qryFltr.SetupTimeStart != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".setup_time >= ?", qryFltr.SetupTimeStart) + q = q.Where("setup_time >= ?", qryFltr.SetupTimeStart) } if qryFltr.SetupTimeEnd != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".setup_time < ?", qryFltr.SetupTimeEnd) + q = q.Where("setup_time < ?", qryFltr.SetupTimeEnd) } if qryFltr.AnswerTimeStart != nil && !qryFltr.AnswerTimeStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".answer_time >= ?", qryFltr.AnswerTimeStart) + q = q.Where("answer_time >= ?", qryFltr.AnswerTimeStart) } if qryFltr.AnswerTimeEnd != nil && !qryFltr.AnswerTimeEnd.IsZero() { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".answer_time < ?", qryFltr.AnswerTimeEnd) + q = q.Where("answer_time < ?", qryFltr.AnswerTimeEnd) } if qryFltr.CreatedAtStart != nil && !qryFltr.CreatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".created_at >= ?", qryFltr.CreatedAtStart) + q = q.Where("created_at >= ?", qryFltr.CreatedAtStart) } if qryFltr.CreatedAtEnd != nil && !qryFltr.CreatedAtEnd.IsZero() { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".created_at < ?", qryFltr.CreatedAtEnd) + q = q.Where("created_at < ?", qryFltr.CreatedAtEnd) } if qryFltr.UpdatedAtStart != nil && !qryFltr.UpdatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".updated_at >= ?", qryFltr.UpdatedAtStart) + q = q.Where("updated_at >= ?", qryFltr.UpdatedAtStart) } if qryFltr.UpdatedAtEnd != nil && !qryFltr.UpdatedAtEnd.IsZero() { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - q = q.Where(tblName+".updated_at < ?", qryFltr.UpdatedAtEnd) + q = q.Where("updated_at < ?", qryFltr.UpdatedAtEnd) } - if qryFltr.MinUsage != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS + if len(qryFltr.MinUsage) != 0 { + if minUsage, err := utils.ParseDurationWithSecs(qryFltr.MinUsage); err != nil { + return nil, 0, err + } else { + q = q.Where("usage >= ?", minUsage.Seconds()) } - q = q.Where(tblName+".usage >= ?", qryFltr.MinUsage) } - if qryFltr.MaxUsage != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS + if len(qryFltr.MaxUsage) != 0 { + if maxUsage, err := utils.ParseDurationWithSecs(qryFltr.MaxUsage); err != nil { + return nil, 0, err + } else { + q = q.Where("usage < ?", maxUsage.Seconds()) } - q = q.Where(tblName+".usage < ?", qryFltr.MaxUsage) + } - if qryFltr.MinPdd != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS + if len(qryFltr.MinPDD) != 0 { + if minPDD, err := utils.ParseDurationWithSecs(qryFltr.MinPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd >= ?", minPDD.Seconds()) } - q = q.Where(tblName+".pdd >= ?", qryFltr.MinPdd) + } - if qryFltr.MaxPdd != nil { - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS + if len(qryFltr.MaxPDD) != 0 { + if maxPDD, err := utils.ParseDurationWithSecs(qryFltr.MaxPDD); err != nil { + return nil, 0, err + } else { + q = q.Where("pdd < ?", maxPDD.Seconds()) } - q = q.Where(tblName+".pdd < ?", qryFltr.MaxPdd) } if qryFltr.MinCost != nil { if qryFltr.MaxCost == nil { - q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost) + q = q.Where("cost >= ?", *qryFltr.MinCost) } else if *qryFltr.MinCost == 0.0 && *qryFltr.MaxCost == -1.0 { // Special case when we want to skip errors - q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost >= 0.0 )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS)) + q = q.Where("( cost IS NULL OR cost >= 0.0 )") } else { - q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost) - q = q.Where(utils.TBL_RATED_CDRS+".cost < ?", *qryFltr.MaxCost) + q = q.Where("cost >= ?", *qryFltr.MinCost) + q = q.Where("cost < ?", *qryFltr.MaxCost) } } else if qryFltr.MaxCost != nil { if *qryFltr.MaxCost == -1.0 { // Non-rated CDRs - q = q.Where(utils.TBL_RATED_CDRS + ".cost IS NULL") // Need to include it otherwise all CDRs will be returned + q = q.Where("cost IS NULL") // Need to include it otherwise all CDRs will be returned } else { // Above limited CDRs, since MinCost is empty, make sure we query also NULL cost - q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost < %f )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, *qryFltr.MaxCost)) + q = q.Where(fmt.Sprintf("( cost IS NULL OR cost < %f )", *qryFltr.MaxCost)) } } if qryFltr.Paginator.Limit != nil { @@ -1008,402 +927,73 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, } // Execute query - rows, err := q.Rows() - if err != nil { - return nil, 0, err - } - for rows.Next() { - var cgrid, tor, accid, cdrhost, cdrsrc, reqtype, direction, tenant, category, account, subject, destination, runid, ccTor, - ccDirection, ccTenant, ccCategory, ccAccount, ccSubject, ccDestination, ccSupplier, ccDisconnectCause sql.NullString - var extraFields, ccTimespansBytes []byte - var setupTime, answerTime mysql.NullTime - var orderid int64 - var usage, pdd, cost, ccCost sql.NullFloat64 + results := make([]*TBLCDRs, 0) + q.Find(&results) + + for _, result := range results { var extraFieldsMp map[string]string - var ccTimespans TimeSpans - if err := rows.Scan(&cgrid, &orderid, &tor, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &category, &account, &subject, &destination, - &setupTime, &answerTime, &usage, &pdd, &ccSupplier, &ccDisconnectCause, - &extraFields, &runid, &cost, &ccTor, &ccDirection, &ccTenant, &ccCategory, &ccAccount, &ccSubject, &ccDestination, &ccCost, &ccTimespansBytes); err != nil { - return nil, 0, err + 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 len(extraFields) != 0 { - if err := json.Unmarshal(extraFields, &extraFieldsMp); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %v, error: %s", cgrid.String, runid.String, err.Error()) + var callCost CallCost + if len(result.CostDetails) != 0 { + 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()) } } - if len(ccTimespansBytes) != 0 { - if err := json.Unmarshal(ccTimespansBytes, &ccTimespans); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal callcost error for cgrid: %s, runid: %v, error: %s", cgrid.String, runid.String, err.Error()) - } - } - usageDur, _ := time.ParseDuration(strconv.FormatFloat(usage.Float64, 'f', -1, 64) + "s") - pddDur, _ := time.ParseDuration(strconv.FormatFloat(pdd.Float64, 'f', -1, 64) + "s") - storCdr := &StoredCdr{ - CgrId: cgrid.String, OrderId: orderid, TOR: tor.String, AccId: accid.String, CdrHost: cdrhost.String, CdrSource: cdrsrc.String, ReqType: reqtype.String, - Direction: direction.String, Tenant: tenant.String, - Category: category.String, Account: account.String, Subject: subject.String, Destination: destination.String, - SetupTime: setupTime.Time, AnswerTime: answerTime.Time, Usage: usageDur, Pdd: pddDur, Supplier: ccSupplier.String, DisconnectCause: ccDisconnectCause.String, - ExtraFields: extraFieldsMp, MediationRunId: runid.String, RatedAccount: ccAccount.String, RatedSubject: ccSubject.String, Cost: cost.Float64, - } - if ccTimespans != nil { - storCdr.CostDetails = &CallCost{Direction: ccDirection.String, Category: ccCategory.String, Tenant: ccTenant.String, Subject: ccSubject.String, Account: ccAccount.String, Destination: ccDestination.String, TOR: ccTor.String, - Cost: ccCost.Float64, Timespans: ccTimespans} - } - if !cost.Valid { //There was no cost provided, will fakely insert 0 if we do not handle it and reflect on re-rating - storCdr.Cost = -1 + usageDur, _ := time.ParseDuration(strconv.FormatFloat(result.Usage, 'f', -1, 64) + "s") + pddDur, _ := time.ParseDuration(strconv.FormatFloat(result.Pdd, 'f', -1, 64) + "s") + 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, + ExtraInfo: result.ExtraInfo, } cdrs = append(cdrs, storCdr) } return cdrs, 0, nil } -/*func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, int64, error) { - var cdrs []*StoredCdr - // Select string - var selectStr string - if qryFltr.FilterOnRated { // We use different tables to query account data in case of derived - selectTmpl := template.Must(template.New("select").Parse("{{.Pr}}.cgrid,{{.Pr}}.id,{{.Pr}}.tor,{{.Pr}}.accid,{{.Pr}}.cdrhost,{{.Pr}}.cdrsource,{{.Rc}}.reqtype,{{.Rc}}.direction,{{.Rc}}.tenant,{{.Rc}}.category,{{.Rc}}.account,{{.Rc}}.subject,{{.Rc}}.destination,{{.Rc}}.setup_time,{{.Rc}}.answer_time,{{.Rc}}.usage,{{.Rc}}.pdd,{{.Rc}}.supplier,{{.Rc}}.disconnect_cause,{{.Ex}}.extra_fields,{{.Rc}}.runid,{{.Rc}}.cost,{{.Cd}}.tor,{{.Cd}}.direction,{{.Cd}}.tenant,{{.Cd}}.category,{{.Cd}}.account,{{.Cd}}.subject,{{.Cd}}.destination,{{.Cd}}.cost,{{.Cd}}.timespans")) - var selectBuf bytes.Buffer - selectTmpl.Execute(&selectBuf, &struct { - Pr string - Ex string - Rc string - Cd string - }{utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_RATED_CDRS, - utils.TBL_COST_DETAILS}) - selectStr = selectBuf.String() - } else { - selectTmpl := template.Must(template.New("select").Parse("{{.Pr}}.cgrid,{{.Pr}}.id,{{.Pr}}.tor,{{.Pr}}.accid,{{.Pr}}.cdrhost,{{.Pr}}.cdrsource,{{.Pr}}.reqtype,{{.Pr}}.direction,{{.Pr}}.tenant,{{.Pr}}.category,{{.Pr}}.account,{{.Pr}}.subject,{{.Pr}}.destination,{{.Pr}}.setup_time,{{.Pr}}.answer_time,{{.Pr}}.usage,{{.Pr}}.pdd,{{.Pr}}.supplier,{{.Pr}}.disconnect_cause,{{.Ex}}.extra_fields,{{.Rc}}.runid,{{.Rc}}.cost,{{.Cd}}.tor,{{.Cd}}.direction,{{.Cd}}.tenant,{{.Cd}}.category,{{.Cd}}.account,{{.Cd}}.subject,{{.Cd}}.destination,{{.Cd}}.cost,{{.Cd}}.timespans")) - var selectBuf bytes.Buffer - selectTmpl.Execute(&selectBuf, &struct { - Pr string - Ex string - Rc string - Cd string - }{utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_RATED_CDRS, - utils.TBL_COST_DETAILS}) - selectStr = selectBuf.String() - } - // Join string - selectTmpl := template.Must(template.New("join").Parse("LEFT JOIN {{.Ex}} ON {{.Pr}}.cgrid={{.Ex}}.cgrid LEFT JOIN {{.Rc}} ON {{.Pr}}.cgrid={{.Rc}}.cgrid LEFT JOIN {{.Cd}} ON {{.Rc}}.cgrid={{.Cd}}.cgrid AND {{.Rc}}.runid={{.Cd}}.runid")) - var joinBuf bytes.Buffer - selectTmpl.Execute(&joinBuf, &struct { - Pr string - Ex string - Rc string - Cd string - }{utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_RATED_CDRS, - utils.TBL_COST_DETAILS}) - joinStr := joinBuf.String() - q := self.db.Table(utils.TBL_CDRS_PRIMARY).Select(selectStr).Joins(joinStr) - if qryFltr.Unscoped { - q = q.Unscoped() - } else { - // Query filter - for _, tblName := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_COST_DETAILS, utils.TBL_RATED_CDRS} { - q = q.Where(fmt.Sprintf("(%s.deleted_at IS NULL OR %s.deleted_at <= '0001-01-02')", tblName, tblName)) // Soft deletes - } - } - tblName := utils.TBL_CDRS_PRIMARY - if qryFltr.FilterOnRated { - tblName = utils.TBL_RATED_CDRS - } - // Add filters, use in to replace the high number of ORs - if len(qryFltr.CgrIds) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cgrid in (?)", qryFltr.CgrIds) - } - if len(qryFltr.NotCgrIds) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cgrid not in (?)", qryFltr.NotCgrIds) - } - if len(qryFltr.RunIds) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".runid in (?)", qryFltr.RunIds) - } - if len(qryFltr.NotRunIds) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".runid not in (?)", qryFltr.NotRunIds) - } - if len(qryFltr.Tors) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".tor in (?)", qryFltr.Tors) - } - if len(qryFltr.NotTors) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".tor not in (?)", qryFltr.NotTors) - } - if len(qryFltr.CdrHosts) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrhost in (?)", qryFltr.CdrHosts) - } - if len(qryFltr.NotCdrHosts) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrhost not in (?)", qryFltr.NotCdrHosts) - } - if len(qryFltr.CdrSources) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrsource in (?)", qryFltr.CdrSources) - } - if len(qryFltr.NotCdrSources) != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".cdrsource not in (?)", qryFltr.NotCdrSources) - } - if len(qryFltr.ReqTypes) != 0 { - q = q.Where(tblName+".reqtype in (?)", qryFltr.ReqTypes) - } - if len(qryFltr.NotReqTypes) != 0 { - q = q.Where(tblName+".reqtype not in (?)", qryFltr.NotReqTypes) - } - if len(qryFltr.Directions) != 0 { - q = q.Where(tblName+".direction in (?)", qryFltr.Directions) - } - if len(qryFltr.NotDirections) != 0 { - q = q.Where(tblName+".direction not in (?)", qryFltr.NotDirections) - } - if len(qryFltr.Tenants) != 0 { - q = q.Where(tblName+".tenant in (?)", qryFltr.Tenants) - } - if len(qryFltr.NotTenants) != 0 { - q = q.Where(tblName+".tenant not in (?)", qryFltr.NotTenants) - } - if len(qryFltr.Categories) != 0 { - q = q.Where(tblName+".category in (?)", qryFltr.Categories) - } - if len(qryFltr.NotCategories) != 0 { - q = q.Where(tblName+".category not in (?)", qryFltr.NotCategories) - } - if len(qryFltr.Accounts) != 0 { - q = q.Where(tblName+".account in (?)", qryFltr.Accounts) - } - if len(qryFltr.NotAccounts) != 0 { - q = q.Where(tblName+".account not in (?)", qryFltr.NotAccounts) - } - if len(qryFltr.Subjects) != 0 { - q = q.Where(tblName+".subject in (?)", qryFltr.Subjects) - } - if len(qryFltr.NotSubjects) != 0 { - q = q.Where(tblName+".subject not in (?)", qryFltr.NotSubjects) - } - if len(qryFltr.DestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm - qIds := bytes.NewBufferString("(") - for idx, destPrefix := range qryFltr.DestPrefixes { - if idx != 0 { - qIds.WriteString(" OR") - } - qIds.WriteString(fmt.Sprintf(" %s.destination LIKE '%s%%'", tblName, destPrefix)) - } - qIds.WriteString(" )") - q = q.Where(qIds.String()) - } - if len(qryFltr.NotDestPrefixes) != 0 { // A bit ugly but still more readable than scopes provided by gorm - qIds := bytes.NewBufferString("(") - for idx, destPrefix := range qryFltr.NotDestPrefixes { - if idx != 0 { - qIds.WriteString(" AND") - } - qIds.WriteString(fmt.Sprintf(" %s.destination not LIKE '%%%s%%'", tblName, destPrefix)) - } - qIds.WriteString(" )") - q = q.Where(qIds.String()) - } - if len(qryFltr.Suppliers) != 0 { - q = q.Where(tblName+".supplier in (?)", qryFltr.Subjects) - } - if len(qryFltr.NotSuppliers) != 0 { - q = q.Where(tblName+".supplier not in (?)", qryFltr.NotSubjects) - } - if len(qryFltr.DisconnectCauses) != 0 { - q = q.Where(tblName+".disconnect_cause in (?)", qryFltr.DisconnectCauses) - } - if len(qryFltr.NotDisconnectCauses) != 0 { - q = q.Where(tblName+".disconnect_cause not in (?)", qryFltr.NotDisconnectCauses) - } - if len(qryFltr.RatedAccounts) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".account in (?)", qryFltr.RatedAccounts) - } - if len(qryFltr.NotRatedAccounts) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".account not in (?)", qryFltr.NotRatedAccounts) - } - if len(qryFltr.RatedSubjects) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".subject in (?)", qryFltr.RatedSubjects) - } - if len(qryFltr.NotRatedSubjects) != 0 { - q = q.Where(utils.TBL_COST_DETAILS+".subject not in (?)", qryFltr.NotRatedSubjects) - } - if len(qryFltr.Costs) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".cost in (?)", qryFltr.Costs) - } - if len(qryFltr.NotCosts) != 0 { - q = q.Where(utils.TBL_RATED_CDRS+".cost not in (?)", qryFltr.NotCosts) - } - if len(qryFltr.ExtraFields) != 0 { // Extra fields searches, implemented as contains in extra field - qIds := bytes.NewBufferString("(") - needOr := false - for field, value := range qryFltr.ExtraFields { - if needOr { - qIds.WriteString(" OR") - } - qIds.WriteString(fmt.Sprintf(` %s.extra_fields LIKE '%%"%s":"%s"%%'`, utils.TBL_CDRS_EXTRA, field, value)) - needOr = true - } - qIds.WriteString(" )") - q = q.Where(qIds.String()) - } - if len(qryFltr.NotExtraFields) != 0 { // Extra fields searches, implemented as contains in extra field - qIds := bytes.NewBufferString("(") - needAnd := false - for field, value := range qryFltr.NotExtraFields { - if needAnd { - qIds.WriteString(" OR") - } - qIds.WriteString(fmt.Sprintf(` %s.extra_fields LIKE '%%"%s":"%s"%%'`, utils.TBL_CDRS_EXTRA, field, value)) - needAnd = true - } - qIds.WriteString(" )") - q = q.Where(qIds.String()) - } - if qryFltr.OrderIdStart != 0 { // Keep backwards compatible by testing 0 value - q = q.Where(utils.TBL_CDRS_PRIMARY+".id >= ?", qryFltr.OrderIdStart) - } - if qryFltr.OrderIdEnd != 0 { - q = q.Where(utils.TBL_CDRS_PRIMARY+".id < ?", qryFltr.OrderIdEnd) - } - if qryFltr.SetupTimeStart != nil { - q = q.Where(tblName+".setup_time >= ?", qryFltr.SetupTimeStart) - } - if qryFltr.SetupTimeEnd != nil { - q = q.Where(tblName+".setup_time < ?", qryFltr.SetupTimeEnd) - } - if qryFltr.AnswerTimeStart != nil && !qryFltr.AnswerTimeStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - q = q.Where(tblName+".answer_time >= ?", qryFltr.AnswerTimeStart) - } - if qryFltr.AnswerTimeEnd != nil && !qryFltr.AnswerTimeEnd.IsZero() { - q = q.Where(tblName+".answer_time < ?", qryFltr.AnswerTimeEnd) - } - if qryFltr.CreatedAtStart != nil && !qryFltr.CreatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - q = q.Where(tblName+".created_at >= ?", qryFltr.CreatedAtStart) - } - if qryFltr.CreatedAtEnd != nil && !qryFltr.CreatedAtEnd.IsZero() { - q = q.Where(tblName+".created_at < ?", qryFltr.CreatedAtEnd) - } - if qryFltr.UpdatedAtStart != nil && !qryFltr.UpdatedAtStart.IsZero() { // With IsZero we keep backwards compatible with ApierV1 - q = q.Where(tblName+".updated_at >= ?", qryFltr.UpdatedAtStart) - } - if qryFltr.UpdatedAtEnd != nil && !qryFltr.UpdatedAtEnd.IsZero() { - q = q.Where(tblName+".updated_at < ?", qryFltr.UpdatedAtEnd) - } - if qryFltr.MinUsage != nil { - q = q.Where(tblName+".usage >= ?", qryFltr.MinUsage) - } - if qryFltr.MaxUsage != nil { - q = q.Where(tblName+".usage < ?", qryFltr.MaxUsage) - } - if qryFltr.MinPdd != nil { - q = q.Where(tblName+".pdd >= ?", qryFltr.MinPdd) - } - if qryFltr.MaxPdd != nil { - q = q.Where(tblName+".pdd < ?", qryFltr.MaxPdd) - } - - if qryFltr.MinCost != nil { - if qryFltr.MaxCost == nil { - q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost) - } else if *qryFltr.MinCost == 0.0 && *qryFltr.MaxCost == -1.0 { // Special case when we want to skip errors - q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost >= 0.0 )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS)) - } else { - q = q.Where(utils.TBL_RATED_CDRS+".cost >= ?", *qryFltr.MinCost) - q = q.Where(utils.TBL_RATED_CDRS+".cost < ?", *qryFltr.MaxCost) - } - } else if qryFltr.MaxCost != nil { - if *qryFltr.MaxCost == -1.0 { // Non-rated CDRs - q = q.Where(utils.TBL_RATED_CDRS + ".cost IS NULL") // Need to include it otherwise all CDRs will be returned - } else { // Above limited CDRs, since MinCost is empty, make sure we query also NULL cost - q = q.Where(fmt.Sprintf("( %s.cost IS NULL OR %s.cost < %f )", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS, *qryFltr.MaxCost)) - } - } - if qryFltr.Paginator.Limit != nil { - q = q.Limit(*qryFltr.Paginator.Limit) - } - if qryFltr.Paginator.Offset != nil { - q = q.Offset(*qryFltr.Paginator.Offset) - } - if qryFltr.Count { - var cnt int64 - if err := q.Count(&cnt).Error; err != nil { - //if err := q.Debug().Count(&cnt).Error; err != nil { - return nil, 0, err - } - return nil, cnt, nil - } - - // Execute query - rows, err := q.Rows() - if err != nil { - return nil, 0, err - } - for rows.Next() { - var cgrid, tor, accid, cdrhost, cdrsrc, reqtype, direction, tenant, category, account, subject, destination, runid, ccTor, - ccDirection, ccTenant, ccCategory, ccAccount, ccSubject, ccDestination, ccSupplier, ccDisconnectCause sql.NullString - var extraFields, ccTimespansBytes []byte - var setupTime, answerTime mysql.NullTime - var orderid int64 - var usage, pdd, cost, ccCost sql.NullFloat64 - var extraFieldsMp map[string]string - var ccTimespans TimeSpans - if err := rows.Scan(&cgrid, &orderid, &tor, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &category, &account, &subject, &destination, - &setupTime, &answerTime, &usage, &pdd, &ccSupplier, &ccDisconnectCause, - &extraFields, &runid, &cost, &ccTor, &ccDirection, &ccTenant, &ccCategory, &ccAccount, &ccSubject, &ccDestination, &ccCost, &ccTimespansBytes); err != nil { - return nil, 0, err - } - if len(extraFields) != 0 { - if err := json.Unmarshal(extraFields, &extraFieldsMp); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %v, error: %s", cgrid.String, runid.String, err.Error()) - } - } - if len(ccTimespansBytes) != 0 { - if err := json.Unmarshal(ccTimespansBytes, &ccTimespans); err != nil { - return nil, 0, fmt.Errorf("JSON unmarshal callcost error for cgrid: %s, runid: %v, error: %s", cgrid.String, runid.String, err.Error()) - } - } - usageDur, _ := time.ParseDuration(strconv.FormatFloat(usage.Float64, 'f', -1, 64) + "s") - pddDur, _ := time.ParseDuration(strconv.FormatFloat(pdd.Float64, 'f', -1, 64) + "s") - storCdr := &StoredCdr{ - CgrId: cgrid.String, OrderId: orderid, TOR: tor.String, AccId: accid.String, CdrHost: cdrhost.String, CdrSource: cdrsrc.String, ReqType: reqtype.String, - Direction: direction.String, Tenant: tenant.String, - Category: category.String, Account: account.String, Subject: subject.String, Destination: destination.String, - SetupTime: setupTime.Time, AnswerTime: answerTime.Time, Usage: usageDur, Pdd: pddDur, Supplier: ccSupplier.String, DisconnectCause: ccDisconnectCause.String, - ExtraFields: extraFieldsMp, MediationRunId: runid.String, RatedAccount: ccAccount.String, RatedSubject: ccSubject.String, Cost: cost.Float64, - } - if ccTimespans != nil { - storCdr.CostDetails = &CallCost{Direction: ccDirection.String, Category: ccCategory.String, Tenant: ccTenant.String, Subject: ccSubject.String, Account: ccAccount.String, Destination: ccDestination.String, TOR: ccTor.String, - Cost: ccCost.Float64, Timespans: ccTimespans} - } - if !cost.Valid { //There was no cost provided, will fakely insert 0 if we do not handle it and reflect on re-rating - storCdr.Cost = -1 - } - cdrs = append(cdrs, storCdr) - } - return cdrs, 0, nil -} -*/ - // Remove CDR data out of all CDR tables based on their cgrid -func (self *SQLStorage) RemStoredCdrs(cgrIds []string) error { +func (self *SQLStorage) RemCDRs(cgrIds []string) error { if len(cgrIds) == 0 { return nil } tx := self.db.Begin() - for _, tblName := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_COST_DETAILS, utils.TBL_RATED_CDRS} { - txI := tx.Table(tblName) - for idx, cgrId := range cgrIds { - if idx == 0 { - txI = txI.Where("cgrid = ?", cgrId) - } else { - txI = txI.Or("cgrid = ?", cgrId) - } - } - if err := txI.Update("deleted_at", time.Now()).Error; err != nil { - tx.Rollback() - return err + + txI := tx.Table(utils.TBL_CDRS) + for idx, cgrId := range cgrIds { + if idx == 0 { + txI = txI.Where("cgrid = ?", cgrId) + } else { + txI = txI.Or("cgrid = ?", cgrId) } } + if err := txI.Update("deleted_at", time.Now()).Error; err != nil { + tx.Rollback() + return err + } tx.Commit() return nil } diff --git a/engine/storage_utils.go b/engine/storage_utils.go index 934e99378..5d550cee9 100644 --- a/engine/storage_utils.go +++ b/engine/storage_utils.go @@ -145,3 +145,11 @@ func ConfigureCdrStorage(db_type, host, port, name, user, pass string, maxConn, } return d, nil } + +// Stores one Cost coming from SM +type SMCost struct { + CGRID string + RunID string + CostSource string + CostDetails *CallCost +} diff --git a/engine/suretax.go b/engine/suretax.go index cbf7d3666..b112b3fac 100644 --- a/engine/suretax.go +++ b/engine/suretax.go @@ -36,7 +36,7 @@ import ( var sureTaxClient *http.Client // Cache the client here if in use // Init a new request to be sent out to SureTax -func NewSureTaxRequest(cdr *StoredCdr, stCfg *config.SureTaxCfg) (*SureTaxRequest, error) { +func NewSureTaxRequest(cdr *CDR, stCfg *config.SureTaxCfg) (*SureTaxRequest, error) { if stCfg == nil { return nil, errors.New("Invalid SureTax config.") } @@ -176,7 +176,7 @@ type STTaxItem struct { TaxAmount string // Tax Amount } -func SureTaxProcessCdr(cdr *StoredCdr) error { +func SureTaxProcessCdr(cdr *CDR) error { stCfg := config.CgrConfig().SureTaxCfg() if stCfg == nil { return errors.New("Invalid SureTax configuration") diff --git a/engine/suretax_test.go b/engine/suretax_test.go index c6f897814..8e9fce485 100644 --- a/engine/suretax_test.go +++ b/engine/suretax_test.go @@ -29,12 +29,13 @@ import ( ) func TestNewSureTaxRequest(t *testing.T) { - cgrId := utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()) - cdr := &StoredCdr{CgrId: cgrId, OrderId: 123, TOR: utils.VOICE, - AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", + 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), MediationRunId: 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, RatedAccount: "dan", RatedSubject: "dans", Rated: true, + 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, } cfg, _ := config.NewDefaultCGRConfig() stCfg := cfg.SureTaxCfg() @@ -48,7 +49,7 @@ func TestNewSureTaxRequest(t *testing.T) { DataMonth: "11", TotalRevenue: 1.01, ReturnFileCode: "0", - ClientTracking: cgrId, + ClientTracking: CGRID, ResponseGroup: "03", ResponseType: "D4", ItemList: []*STRequestItem{ diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 8c1467e0c..5f22f0a2a 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -922,7 +922,7 @@ func (tpr *TpReader) LoadDerivedChargersFiltered(filter *TpDerivedCharger, save tag := tpDcs.GetDerivedChargersKey() if _, hasIt := tpr.derivedChargers[tag]; !hasIt { tpr.derivedChargers[tag] = &utils.DerivedChargers{ - DestinationIds: make(utils.StringMap), + DestinationIDs: make(utils.StringMap), Chargers: make([]*utils.DerivedCharger, 0), } // Load object map since we use this method also from LoadDerivedChargers } @@ -933,7 +933,7 @@ func (tpr *TpReader) LoadDerivedChargersFiltered(filter *TpDerivedCharger, save if err != nil { return err } - tpr.derivedChargers[tag].DestinationIds.Copy(utils.ParseStringMap(tpDcs.DestinationIds)) + tpr.derivedChargers[tag].DestinationIDs.Copy(utils.ParseStringMap(tpDcs.DestinationIds)) tpr.derivedChargers[tag].Chargers = append(tpr.derivedChargers[tag].Chargers, dc) } } diff --git a/engine/units_counter_test.go b/engine/units_counter_test.go index ef8a52d3a..be8b3a49c 100644 --- a/engine/units_counter_test.go +++ b/engine/units_counter_test.go @@ -245,3 +245,87 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) { t.Errorf("Error adding unit counters: %v", len(a.UnitCounters)) } } + +/* +func TestUnitCountersResetCounterById(t *testing.T) { + a := &Account{ + ActionTriggers: ActionTriggers{ + &ActionTrigger{ + ID: "TestTR1", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + ID: "TestTR11", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.MONETARY, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + ID: "TestTR2", + ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + ID: "TestTR3", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.VOICE, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + ID: "TestTR4", + ThresholdType: utils.TRIGGER_MAX_BALANCE_COUNTER, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + &ActionTrigger{ + ID: "TestTR5", + ThresholdType: utils.TRIGGER_MAX_BALANCE, + BalanceType: utils.SMS, + BalanceDirections: utils.NewStringMap(utils.OUT, utils.IN), + BalanceWeight: 10, + }, + }, + } + a.InitCounters() + a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil) + + if len(a.UnitCounters) != 4 || + len(a.UnitCounters[0].Balances) != 2 || + a.UnitCounters[0].Balances[0].Value != 10 || + a.UnitCounters[0].Balances[1].Value != 10 { + for _, uc := range a.UnitCounters { + t.Logf("UC: %+v", uc) + for _, b := range uc.Balances { + t.Logf("B: %+v", b) + } + } + t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters)) + } + a.UnitCounters.resetCounters(&Action{ + BalanceType: utils.MONETARY, + Balance: &Balance{ + Id: "TestTR11", + }, + }) + if len(a.UnitCounters) != 4 || + len(a.UnitCounters[0].Balances) != 2 || + a.UnitCounters[0].Balances[0].Value != 10 || + a.UnitCounters[0].Balances[1].Value != 0 { + for _, uc := range a.UnitCounters { + t.Logf("UC: %+v", uc) + for _, b := range uc.Balances { + t.Logf("B: %+v", b) + } + } + t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters)) + } +} +*/ diff --git a/engine/users_test.go b/engine/users_test.go index a9e640351..a22401014 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -582,17 +582,17 @@ func TestUsersAddUpdateRemoveIndexes(t *testing.T) { func TestUsersUsageRecordGetLoadUserProfile(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, - ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, - "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, - "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13"}, + "test:user": map[string]string{utils.TOR: "01", "RequestType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{utils.TOR: "02", "RequestType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{utils.TOR: "03", "RequestType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{utils.TOR: "04", "RequestType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13"}, }, index: make(map[string]map[string]bool), } ur := &UsageRecord{ - TOR: utils.USERS, - ReqType: utils.USERS, + ToR: utils.USERS, + RequestType: utils.USERS, Direction: "*out", Tenant: "", Category: "call", @@ -609,8 +609,8 @@ func TestUsersUsageRecordGetLoadUserProfile(t *testing.T) { t.Error("Error loading user profile: ", err) } expected := &UsageRecord{ - TOR: "04", - ReqType: "4", + ToR: "04", + RequestType: "4", Direction: "*out", Tenant: "", Category: "call", @@ -626,20 +626,20 @@ func TestUsersUsageRecordGetLoadUserProfile(t *testing.T) { } } -func TestUsersExternalCdrGetLoadUserProfileExtraFields(t *testing.T) { +func TestUsersExternalCDRGetLoadUserProfileExtraFields(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, - ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, - "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, - "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "1"}, + "test:user": map[string]string{utils.TOR: "01", "RequestType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{utils.TOR: "02", "RequestType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{utils.TOR: "03", "RequestType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{utils.TOR: "04", "RequestType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "1"}, }, index: make(map[string]map[string]bool), } - ur := &ExternalCdr{ - TOR: utils.USERS, - ReqType: utils.USERS, + ur := &ExternalCDR{ + ToR: utils.USERS, + RequestType: utils.USERS, Direction: "*out", Tenant: "", Category: "call", @@ -658,9 +658,9 @@ func TestUsersExternalCdrGetLoadUserProfileExtraFields(t *testing.T) { if err != nil { t.Error("Error loading user profile: ", err) } - expected := &ExternalCdr{ - TOR: "04", - ReqType: "4", + expected := &ExternalCDR{ + ToR: "04", + RequestType: "4", Direction: "*out", Tenant: "", Category: "call", @@ -679,20 +679,20 @@ func TestUsersExternalCdrGetLoadUserProfileExtraFields(t *testing.T) { } } -func TestUsersExternalCdrGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { +func TestUsersExternalCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, - ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, - "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, - "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "2"}, + "test:user": map[string]string{utils.TOR: "01", "RequestType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{utils.TOR: "02", "RequestType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{utils.TOR: "03", "RequestType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{utils.TOR: "04", "RequestType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "2"}, }, index: make(map[string]map[string]bool), } - ur := &ExternalCdr{ - TOR: utils.USERS, - ReqType: utils.USERS, + ur := &ExternalCDR{ + ToR: utils.USERS, + RequestType: utils.USERS, Direction: "*out", Tenant: "", Category: "call", @@ -713,20 +713,20 @@ func TestUsersExternalCdrGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { } } -func TestUsersExternalCdrGetLoadUserProfileExtraFieldsSet(t *testing.T) { +func TestUsersExternalCDRGetLoadUserProfileExtraFieldsSet(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, - ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, - "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, - "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "1", "Best": "BestValue"}, + "test:user": map[string]string{utils.TOR: "01", "RequestType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{utils.TOR: "02", "RequestType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{utils.TOR: "03", "RequestType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{utils.TOR: "04", "RequestType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "1", "Best": "BestValue"}, }, index: make(map[string]map[string]bool), } - ur := &ExternalCdr{ - TOR: utils.USERS, - ReqType: utils.USERS, + ur := &ExternalCDR{ + ToR: utils.USERS, + RequestType: utils.USERS, Direction: "*out", Tenant: "", Category: "call", @@ -746,9 +746,9 @@ func TestUsersExternalCdrGetLoadUserProfileExtraFieldsSet(t *testing.T) { if err != nil { t.Error("Error loading user profile: ", err) } - expected := &ExternalCdr{ - TOR: "04", - ReqType: "4", + expected := &ExternalCDR{ + ToR: "04", + RequestType: "4", Direction: "*out", Tenant: "", Category: "call", @@ -771,9 +771,9 @@ func TestUsersExternalCdrGetLoadUserProfileExtraFieldsSet(t *testing.T) { func TestUsersCallDescLoadUserProfile(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "cgrates.org:dan": map[string]string{"ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"}, - "cgrates.org:danvoice": map[string]string{"TOR": "*voice", "ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"}, - "cgrates:rif": map[string]string{"ReqType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"}, + "cgrates.org:dan": map[string]string{"RequestType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"}, + "cgrates.org:danvoice": map[string]string{utils.TOR: "*voice", "RequestType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"}, + "cgrates:rif": map[string]string{"RequestType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"}, }, index: make(map[string]map[string]bool), } @@ -809,19 +809,19 @@ func TestUsersCallDescLoadUserProfile(t *testing.T) { } } -func TestUsersStoredCdrLoadUserProfile(t *testing.T) { +func TestUsersCDRLoadUserProfile(t *testing.T) { userService = &UserMap{ table: map[string]map[string]string{ - "cgrates.org:dan": map[string]string{"ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"}, - "cgrates.org:danvoice": map[string]string{"TOR": "*voice", "ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"}, - "cgrates:rif": map[string]string{"ReqType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"}, + "cgrates.org:dan": map[string]string{"RequestType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"}, + "cgrates.org:danvoice": map[string]string{utils.TOR: "*voice", "RequestType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"}, + "cgrates:rif": map[string]string{"RequestType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"}, }, index: make(map[string]map[string]bool), } startTime := time.Now() - cdr := &StoredCdr{ - TOR: "*sms", - ReqType: utils.USERS, + cdr := &CDR{ + ToR: "*sms", + RequestType: utils.USERS, Tenant: utils.USERS, Category: utils.USERS, Account: utils.USERS, @@ -832,9 +832,9 @@ func TestUsersStoredCdrLoadUserProfile(t *testing.T) { Usage: time.Duration(1) * time.Minute, ExtraFields: map[string]string{"Cli": "+4986517174963"}, } - expected := &StoredCdr{ - TOR: "*sms", - ReqType: "*prepaid", + expected := &CDR{ + ToR: "*sms", + RequestType: "*prepaid", Tenant: "cgrates.org", Category: "call1", Account: "dan", diff --git a/general_tests/auth_test.go b/general_tests/auth_test.go index d976c5c8e..b9069716e 100644 --- a/general_tests/auth_test.go +++ b/general_tests/auth_test.go @@ -93,7 +93,7 @@ RP_ANY,DR_ANY_1CNT,*any,10` } func TestAuthPostpaidNoAcnt(t *testing.T) { - cdr := &engine.StoredCdr{TOR: utils.VOICE, ReqType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", 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 @@ -104,7 +104,7 @@ func TestAuthPostpaidNoAcnt(t *testing.T) { func TestAuthPostpaidNoDestination(t *testing.T) { // Test subject which does not have destination attached - cdr := &engine.StoredCdr{TOR: utils.VOICE, ReqType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", 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 @@ -115,7 +115,7 @@ func TestAuthPostpaidNoDestination(t *testing.T) { func TestAuthPostpaidFallbackDest(t *testing.T) { // Test subject which has fallback for destination - cdr := &engine.StoredCdr{TOR: utils.VOICE, ReqType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", 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 @@ -128,7 +128,7 @@ func TestAuthPostpaidFallbackDest(t *testing.T) { func TestAuthPostpaidWithDestination(t *testing.T) { // Test subject which does not have destination attached - cdr := &engine.StoredCdr{TOR: utils.VOICE, ReqType: utils.META_POSTPAID, Direction: "*out", Tenant: "cgrates.org", + cdr := &engine.CDR{ToR: utils.VOICE, RequestType: utils.META_POSTPAID, Direction: "*out", 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/engine/cdrs_local_test.go b/general_tests/cdrs_replication_it_test.go similarity index 72% rename from engine/cdrs_local_test.go rename to general_tests/cdrs_replication_it_test.go index 7c1e631dd..66a682f7a 100644 --- a/engine/cdrs_local_test.go +++ b/general_tests/cdrs_replication_it_test.go @@ -16,14 +16,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ -package engine +package general_tests import ( + "flag" "path" "testing" "time" "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" "github.com/cgrates/rpcclient" ) @@ -31,12 +33,10 @@ import ( var cdrsMasterCfgPath, cdrsSlaveCfgPath string var cdrsMasterCfg, cdrsSlaveCfg *config.CGRConfig -//var cdrsHttpJsonRpc *rpcclient.RpcClient - -var waitRater = 500 +var testIntegration = flag.Bool("integration", false, "Perform the tests in integration mode, not by default.") // This flag will be passed here via "go test -local" args func TestCdrsInitConfig(t *testing.T) { - if !*testLocal { + if !*testIntegration { return } var err error @@ -52,64 +52,64 @@ func TestCdrsInitConfig(t *testing.T) { // InitDb so we can rely on count func TestCdrsInitCdrDb(t *testing.T) { - if !*testLocal { + if !*testIntegration { return } - if err := InitStorDb(cdrsMasterCfg); err != nil { + if err := engine.InitStorDb(cdrsMasterCfg); err != nil { t.Fatal(err) } - if err := InitStorDb(cdrsSlaveCfg); err != nil { + if err := engine.InitStorDb(cdrsSlaveCfg); err != nil { t.Fatal(err) } } func TestCdrsStartMasterEngine(t *testing.T) { - if !*testLocal { + if !*testIntegration { return } - if _, err := StopStartEngine(cdrsMasterCfgPath, waitRater); err != nil { + if _, err := engine.StopStartEngine(cdrsMasterCfgPath, *waitRater); err != nil { t.Fatal(err) } } func TestCdrsStartSlaveEngine(t *testing.T) { - if !*testLocal { + if !*testIntegration { return } - if _, err := StartEngine(cdrsSlaveCfgPath, waitRater); err != nil { + if _, err := engine.StartEngine(cdrsSlaveCfgPath, *waitRater); err != nil { t.Fatal(err) } } // Connect rpc client to rater func TestCdrsHttpCdrReplication(t *testing.T) { - if !*testLocal { + if !*testIntegration { return } cdrsMasterRpc, err := rpcclient.NewRpcClient("tcp", cdrsMasterCfg.RPCJSONListen, 1, 1, "json", nil) if err != nil { t.Fatal("Could not connect to rater: ", err.Error()) } - testCdr1 := &StoredCdr{CgrId: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "httpjsonrpc1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_PSEUDOPREPAID, + 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", 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"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} + RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} var reply string if err := cdrsMasterRpc.Call("CdrsV2.ProcessCdr", testCdr1, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - time.Sleep(time.Duration(waitRater) * time.Millisecond) + time.Sleep(time.Duration(*waitRater) * time.Millisecond) cdrsSlaveRpc, err := rpcclient.NewRpcClient("tcp", "127.0.0.1:12012", 1, 1, "json", nil) if err != nil { t.Fatal("Could not connect to rater: ", err.Error()) } // ToDo: Fix cdr_http to be compatible with rest of processCdr methods - var rcvedCdrs []*ExternalCdr - if err := cdrsSlaveRpc.Call("ApierV2.GetCdrs", utils.RpcCdrsFilter{CgrIds: []string{testCdr1.CgrId}, RunIds: []string{utils.META_DEFAULT}}, &rcvedCdrs); err != nil { + var rcvedCdrs []*engine.ExternalCDR + if err := cdrsSlaveRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{CGRIDs: []string{testCdr1.CGRID}, RunIDs: []string{utils.META_DEFAULT}}, &rcvedCdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(rcvedCdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(rcvedCdrs)) @@ -117,11 +117,11 @@ func TestCdrsHttpCdrReplication(t *testing.T) { rcvSetupTime, _ := utils.ParseTimeDetectLayout(rcvedCdrs[0].SetupTime, "") rcvAnswerTime, _ := utils.ParseTimeDetectLayout(rcvedCdrs[0].AnswerTime, "") //rcvUsage, _ := utils.ParseDurationWithSecs(rcvedCdrs[0].Usage) - if rcvedCdrs[0].CgrId != testCdr1.CgrId || - rcvedCdrs[0].TOR != testCdr1.TOR || - rcvedCdrs[0].CdrHost != testCdr1.CdrHost || - rcvedCdrs[0].CdrSource != testCdr1.CdrSource || - rcvedCdrs[0].ReqType != testCdr1.ReqType || + if rcvedCdrs[0].CGRID != testCdr1.CGRID || + rcvedCdrs[0].ToR != testCdr1.ToR || + rcvedCdrs[0].OriginHost != testCdr1.OriginHost || + rcvedCdrs[0].Source != testCdr1.Source || + rcvedCdrs[0].RequestType != testCdr1.RequestType || rcvedCdrs[0].Direction != testCdr1.Direction || rcvedCdrs[0].Tenant != testCdr1.Tenant || rcvedCdrs[0].Category != testCdr1.Category || @@ -131,7 +131,7 @@ func TestCdrsHttpCdrReplication(t *testing.T) { !rcvSetupTime.Equal(testCdr1.SetupTime) || !rcvAnswerTime.Equal(testCdr1.AnswerTime) || //rcvUsage != 10 || - rcvedCdrs[0].MediationRunId != testCdr1.MediationRunId { + rcvedCdrs[0].RunID != testCdr1.RunID { //rcvedCdrs[0].Cost != testCdr1.Cost || //!reflect.DeepEqual(rcvedCdrs[0].ExtraFields, testCdr1.ExtraFields) { t.Errorf("Expected: %+v, received: %+v", testCdr1, rcvedCdrs[0]) diff --git a/general_tests/fsevcorelate_test.go b/general_tests/fsevcorelate_test.go index 0928ebc93..898be1012 100644 --- a/general_tests/fsevcorelate_test.go +++ b/general_tests/fsevcorelate_test.go @@ -134,7 +134,7 @@ variable_effective_caller_id_number: 1001 variable_outbound_caller_id_name: FreeSWITCH variable_outbound_caller_id_number: 0000000000 variable_callgroup: techsupport -variable_cgr_reqtype: *prepaid +variable_cgr_RequestType: *prepaid variable_user_name: 1001 variable_domain_name: 192.168.56.66 variable_sip_from_user_stripped: 1001 @@ -211,7 +211,7 @@ variable_read_codec: G722 variable_read_rate: 16000 variable_sip_local_sdp_str: v%3D0%0Ao%3DFreeSWITCH%201396951687%201396951689%20IN%20IP4%20192.168.56.74%0As%3DFreeSWITCH%0Ac%3DIN%20IP4%20192.168.56.74%0At%3D0%200%0Am%3Daudio%2032534%20RTP/AVP%209%20101%0Aa%3Drtpmap%3A9%20G722/8000%0Aa%3Drtpmap%3A101%20telephone-event/8000%0Aa%3Dfmtp%3A101%200-16%0Aa%3Dptime%3A20%0Aa%3Dsendrecv%0A` -var jsonCdr = []byte(`{"core-uuid":"feef0b51-7fdf-4c4a-878e-aff233752de2","channel_data":{"state":"CS_REPORTING","direction":"inbound","state_number":"11","flags":"0=1;1=1;3=1;36=1;37=1;39=1;42=1;47=1;52=1;73=1;75=1;94=1","caps":"1=1;2=1;3=1;4=1;5=1;6=1"},"variables":{"direction":"inbound","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","session_id":"5","sip_from_user":"1001","sip_from_uri":"1001@192.168.56.74","sip_from_host":"192.168.56.74","channel_name":"sofia/internal/1001@192.168.56.74","sip_local_network_addr":"192.168.56.74","sip_network_ip":"192.168.56.1","sip_network_port":"5060","sip_received_ip":"192.168.56.1","sip_received_port":"5060","sip_via_protocol":"udp","sip_authorized":"true","Event-Name":"REQUEST_PARAMS","Core-UUID":"feef0b51-7fdf-4c4a-878e-aff233752de2","FreeSWITCH-Hostname":"CGRTest","FreeSWITCH-Switchname":"CGRTest","FreeSWITCH-IPv4":"192.168.178.32","FreeSWITCH-IPv6":"::1","Event-Date-Local":"2014-04-08 21:10:21","Event-Date-GMT":"Tue, 08 Apr 2014 19:10:21 GMT","Event-Date-Timestamp":"1396984221278217","Event-Calling-File":"sofia.c","Event-Calling-Function":"sofia_handle_sip_i_invite","Event-Calling-Line-Number":"8076","Event-Sequence":"1423","sip_number_alias":"1001","sip_auth_username":"1001","sip_auth_realm":"192.168.56.74","number_alias":"1001","requested_domain_name":"192.168.56.66","record_stereo":"true","default_gateway":"example.com","default_areacode":"918","transfer_fallback_extension":"operator","toll_allow":"domestic,international,local","accountcode":"1001","user_context":"default","effective_caller_id_name":"Extension 1001","effective_caller_id_number":"1001","outbound_caller_id_name":"FreeSWITCH","outbound_caller_id_number":"0000000000","callgroup":"techsupport","user_name":"1001","domain_name":"192.168.56.66","sip_from_user_stripped":"1001","sofia_profile_name":"internal","recovery_profile_name":"internal","sip_req_user":"1002","sip_req_uri":"1002@192.168.56.74","sip_req_host":"192.168.56.74","sip_to_user":"1002","sip_to_uri":"1002@192.168.56.74","sip_to_host":"192.168.56.74","sip_contact_params":"transport=udp;registering_acc=192_168_56_74","sip_contact_user":"1001","sip_contact_port":"5060","sip_contact_uri":"1001@192.168.56.1:5060","sip_contact_host":"192.168.56.1","sip_via_host":"192.168.56.1","sip_via_port":"5060","presence_id":"1001@192.168.56.74","ep_codec_string":"G722@8000h@20i@64000b,PCMU@8000h@20i@64000b,PCMA@8000h@20i@64000b,GSM@8000h@20i@13200b","cgr_notify":"+AUTH_OK","max_forwards":"69","transfer_history":"1396984221:caefc538-5da4-4245-8716-112c706383d8:bl_xfer:1002/default/XML","transfer_source":"1396984221:caefc538-5da4-4245-8716-112c706383d8:bl_xfer:1002/default/XML","DP_MATCH":"ARRAY::1002|:1002","call_uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","RFC2822_DATE":"Tue, 08 Apr 2014 21:10:21 +0200","dialed_extension":"1002","export_vars":"RFC2822_DATE,RFC2822_DATE,dialed_extension","ringback":"%(2000,4000,440,480)","transfer_ringback":"local_stream://moh","call_timeout":"30","hangup_after_bridge":"true","continue_on_fail":"true","called_party_callgroup":"techsupport","current_application_data":"user/1002@192.168.56.66","current_application":"bridge","dialed_user":"1002","dialed_domain":"192.168.56.66","inherit_codec":"true","originated_legs":"ARRAY::402f0929-fa14-4a5f-9642-3a1311bb4ddd;Outbound Call;1002|:402f0929-fa14-4a5f-9642-3a1311bb4ddd;Outbound Call;1002","rtp_use_codec_string":"G722,PCMU,PCMA,GSM","sip_use_codec_name":"G722","sip_use_codec_rate":"8000","sip_use_codec_ptime":"20","write_codec":"G722","write_rate":"16000","video_possible":"true","local_media_ip":"192.168.56.74","local_media_port":"32534","advertised_media_ip":"192.168.56.74","sip_use_pt":"9","rtp_use_ssrc":"1431080133","zrtp_secure_media_confirmed_audio":"true","zrtp_sas1_string_audio":"j6ff","switch_m_sdp":"v=0\r\no=1002 0 0 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5020 RTP/AVP 9 0 8 3 101\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:101 telephone-event/8000\r\n","read_codec":"G722","read_rate":"16000","endpoint_disposition":"ANSWER","originate_causes":"ARRAY::402f0929-fa14-4a5f-9642-3a1311bb4ddd;NONE|:402f0929-fa14-4a5f-9642-3a1311bb4ddd;NONE","originate_disposition":"SUCCESS","DIALSTATUS":"SUCCESS","last_bridge_to":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","bridge_channel":"sofia/internal/sip:1002@192.168.56.1:5060","bridge_uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","signal_bond":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","last_sent_callee_id_name":"Outbound Call","last_sent_callee_id_number":"1002","cgr_reqtype":"*prepaid","sip_reinvite_sdp":"v=0\r\no=1001 0 1 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5016 RTP/AVP 96 97 98 9 100 102 0 8 103 3 104 101\r\na=sendonly\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 usedtx=1\r\na=rtpmap:97 SILK/24000\r\na=rtpmap:98 SILK/16000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:100 speex/32000\r\na=rtpmap:102 speex/16000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:103 iLBC/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:104 speex/8000\r\na=rtpmap:101 telephone-event/8000\r\na=extmap:1 urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=zrtp-hash:1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286\r\nm=video 0 RTP/AVP 105 99\r\n","switch_r_sdp":"v=0\r\no=1001 0 1 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5016 RTP/AVP 96 97 98 9 100 102 0 8 103 3 104 101\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 usedtx=1\r\na=rtpmap:97 SILK/24000\r\na=rtpmap:98 SILK/16000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:100 speex/32000\r\na=rtpmap:102 speex/16000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:103 iLBC/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:104 speex/8000\r\na=rtpmap:101 telephone-event/8000\r\na=sendonly\r\na=extmap:1 urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=zrtp-hash:1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286\r\nm=video 0 RTP/AVP 105 99\r\n","r_sdp_audio_zrtp_hash":"1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286","remote_media_ip":"192.168.56.1","remote_media_port":"5016","sip_audio_recv_pt":"9","dtmf_type":"rfc2833","sip_2833_send_payload":"101","sip_2833_recv_payload":"101","sip_local_sdp_str":"v=0\no=FreeSWITCH 1396951687 1396951690 IN IP4 192.168.56.74\ns=FreeSWITCH\nc=IN IP4 192.168.56.74\nt=0 0\nm=audio 32534 RTP/AVP 9 101\na=rtpmap:9 G722/8000\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-16\na=ptime:20\na=sendrecv\n","sip_to_tag":"rXc9vZpv9eFaF","sip_from_tag":"1afc7eca","sip_cseq":"3","sip_call_id":"6691dbf8ffdc02bdacee02bc305d5c71@0:0:0:0:0:0:0:0","sip_full_via":"SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bK-323133-5d083abc0d3f327b9101586e71b5fce4","sip_from_display":"1001","sip_full_from":"\"1001\" ;tag=1afc7eca","sip_full_to":";tag=rXc9vZpv9eFaF","sip_term_status":"200","proto_specific_hangup_cause":"sip:200","sip_term_cause":"16","last_bridge_role":"originator","sip_user_agent":"Jitsi2.5.5065Linux","sip_hangup_disposition":"recv_bye","bridge_hangup_cause":"NORMAL_CLEARING","hangup_cause":"NORMAL_CLEARING","hangup_cause_q850":"16","digits_dialed":"none","start_stamp":"2014-04-08 21:10:21","profile_start_stamp":"2014-04-08 21:10:21","answer_stamp":"2014-04-08 21:10:27","bridge_stamp":"2014-04-08 21:10:27","hold_stamp":"2014-04-08 21:10:27","progress_stamp":"2014-04-08 21:10:21","progress_media_stamp":"2014-04-08 21:10:21","hold_events":"{{1396984227824182,1396984242247995}}","end_stamp":"2014-04-08 21:10:42","start_epoch":"1396984221","start_uepoch":"1396984221278217","profile_start_epoch":"1396984221","profile_start_uepoch":"1396984221377035","answer_epoch":"1396984227","answer_uepoch":"1396984227717006","bridge_epoch":"1396984227","bridge_uepoch":"1396984227737268","last_hold_epoch":"1396984227","last_hold_uepoch":"1396984227824167","hold_accum_seconds":"14","hold_accum_usec":"14423816","hold_accum_ms":"14423","resurrect_epoch":"0","resurrect_uepoch":"0","progress_epoch":"1396984221","progress_uepoch":"1396984221497331","progress_media_epoch":"1396984221","progress_media_uepoch":"1396984221517042","end_epoch":"1396984242","end_uepoch":"1396984242257026","last_app":"bridge","last_arg":"user/1002@192.168.56.66","caller_id":"\"1001\" <1001>","duration":"21","billsec":"15","progresssec":"0","answersec":"6","waitsec":"6","progress_mediasec":"0","flow_billsec":"21","mduration":"20979","billmsec":"14540","progressmsec":"219","answermsec":"6439","waitmsec":"6459","progress_mediamsec":"239","flow_billmsec":"20979","uduration":"20978809","billusec":"14540020","progressusec":"219114","answerusec":"6438789","waitusec":"6459051","progress_mediausec":"238825","flow_billusec":"20978809","rtp_audio_in_raw_bytes":"181360","rtp_audio_in_media_bytes":"180304","rtp_audio_in_packet_count":"1031","rtp_audio_in_media_packet_count":"1025","rtp_audio_in_skip_packet_count":"45","rtp_audio_in_jb_packet_count":"0","rtp_audio_in_dtmf_packet_count":"0","rtp_audio_in_cng_packet_count":"0","rtp_audio_in_flush_packet_count":"6","rtp_audio_in_largest_jb_size":"0","rtp_audio_out_raw_bytes":"165780","rtp_audio_out_media_bytes":"165780","rtp_audio_out_packet_count":"942","rtp_audio_out_media_packet_count":"942","rtp_audio_out_skip_packet_count":"0","rtp_audio_out_dtmf_packet_count":"0","rtp_audio_out_cng_packet_count":"0","rtp_audio_rtcp_packet_count":"0","rtp_audio_rtcp_octet_count":"0"},"app_log":{"applications":[{"app_name":"hash","app_data":"insert/192.168.56.66-spymap/1001/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/1001/1002"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"export","app_data":"RFC2822_DATE=Tue, 08 Apr 2014 21:10:21 +0200"},{"app_name":"park","app_data":""},{"app_name":"hash","app_data":"insert/192.168.56.66-spymap/1001/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/1001/1002"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"export","app_data":"RFC2822_DATE=Tue, 08 Apr 2014 21:10:21 +0200"},{"app_name":"export","app_data":"dialed_extension=1002"},{"app_name":"bind_meta_app","app_data":"1 b s execute_extension::dx XML features"},{"app_name":"bind_meta_app","app_data":"2 b s record_session::/var/lib/freeswitch/recordings/1001.2014-04-08-21-10-21.wav"},{"app_name":"bind_meta_app","app_data":"3 b s execute_extension::cf XML features"},{"app_name":"bind_meta_app","app_data":"4 b s execute_extension::att_xfer XML features"},{"app_name":"set","app_data":"ringback=%(2000,4000,440,480)"},{"app_name":"set","app_data":"transfer_ringback=local_stream://moh"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"set","app_data":"hangup_after_bridge=true"},{"app_name":"set","app_data":"continue_on_fail=true"},{"app_name":"hash","app_data":"insert/192.168.56.66-call_return/1002/1001"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/1002/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"set","app_data":"called_party_callgroup=techsupport"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/techsupport/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/techsupport/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"bridge","app_data":"user/1002@192.168.56.66"}]},"callflow":{"dialplan":"XML","profile_index":"2","extension":{"name":"global","number":"1002","applications":[{"app_name":"hash","app_data":"insert/${domain_name}-spymap/${caller_id_number}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${caller_id_number}/${destination_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/global/${uuid}"},{"app_name":"export","app_data":"RFC2822_DATE=${strftime(%a, %d %b %Y %T %z)}"},{"app_name":"export","app_data":"dialed_extension=1002"},{"app_name":"bind_meta_app","app_data":"1 b s execute_extension::dx XML features"},{"app_name":"bind_meta_app","app_data":"2 b s record_session::/var/lib/freeswitch/recordings/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"},{"app_name":"bind_meta_app","app_data":"3 b s execute_extension::cf XML features"},{"app_name":"bind_meta_app","app_data":"4 b s execute_extension::att_xfer XML features"},{"app_name":"set","app_data":"ringback=${us-ring}"},{"app_name":"set","app_data":"transfer_ringback=local_stream://moh"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"set","app_data":"hangup_after_bridge=true"},{"app_name":"set","app_data":"continue_on_fail=true"},{"app_name":"hash","app_data":"insert/${domain_name}-call_return/${dialed_extension}/${caller_id_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/${dialed_extension}/${uuid}"},{"app_name":"set","app_data":"called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/${called_party_callgroup}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/global/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}"},{"app_name":"bridge","app_data":"user/${dialed_extension}@${domain_name}"},{"last_executed":"true","app_name":"answer","app_data":""},{"app_name":"sleep","app_data":"1000"},{"app_name":"bridge","app_data":"loopback/app=voicemail:default ${domain_name} ${dialed_extension}"}],"current_app":"answer"},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","source":"mod_sofia","context":"default","chan_name":"sofia/internal/1001@192.168.56.74","originatee":{"originatee_caller_profiles":[{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","source":"mod_sofia","context":"default","chan_name":"sofia/internal/sip:1002@192.168.56.1:5060"},{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","source":"mod_sofia","context":"default","chan_name":"sofia/internal/sip:1002@192.168.56.1:5060"}]}},"times":{"created_time":"1396984221278217","profile_created_time":"1396984221377035","progress_time":"1396984221497331","progress_media_time":"1396984221517042","answered_time":"1396984227717006","hangup_time":"1396984242257026","resurrect_time":"0","transfer_time":"0"}},"callflow":{"dialplan":"XML","profile_index":"1","extension":{"name":"global","number":"1002","applications":[{"app_name":"hash","app_data":"insert/${domain_name}-spymap/${caller_id_number}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${caller_id_number}/${destination_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/global/${uuid}"},{"app_name":"export","app_data":"RFC2822_DATE=${strftime(%a, %d %b %Y %T %z)}"},{"app_name":"park","app_data":""}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"","destination_number":"1002","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","source":"mod_sofia","context":"default","chan_name":"sofia/internal/1001@192.168.56.74"},"times":{"created_time":"1396984221278217","profile_created_time":"1396984221278217","progress_time":"0","progress_media_time":"0","answered_time":"0","hangup_time":"0","resurrect_time":"0","transfer_time":"1396984221377035"}}}`) +var jsonCdr = []byte(`{"core-uuid":"feef0b51-7fdf-4c4a-878e-aff233752de2","channel_data":{"state":"CS_REPORTING","direction":"inbound","state_number":"11","flags":"0=1;1=1;3=1;36=1;37=1;39=1;42=1;47=1;52=1;73=1;75=1;94=1","caps":"1=1;2=1;3=1;4=1;5=1;6=1"},"variables":{"direction":"inbound","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","session_id":"5","sip_from_user":"1001","sip_from_uri":"1001@192.168.56.74","sip_from_host":"192.168.56.74","channel_name":"sofia/internal/1001@192.168.56.74","sip_local_network_addr":"192.168.56.74","sip_network_ip":"192.168.56.1","sip_network_port":"5060","sip_received_ip":"192.168.56.1","sip_received_port":"5060","sip_via_protocol":"udp","sip_authorized":"true","Event-Name":"REQUEST_PARAMS","Core-UUID":"feef0b51-7fdf-4c4a-878e-aff233752de2","FreeSWITCH-Hostname":"CGRTest","FreeSWITCH-Switchname":"CGRTest","FreeSWITCH-IPv4":"192.168.178.32","FreeSWITCH-IPv6":"::1","Event-Date-Local":"2014-04-08 21:10:21","Event-Date-GMT":"Tue, 08 Apr 2014 19:10:21 GMT","Event-Date-Timestamp":"1396984221278217","Event-Calling-File":"sofia.c","Event-Calling-Function":"sofia_handle_sip_i_invite","Event-Calling-Line-Number":"8076","Event-Sequence":"1423","sip_number_alias":"1001","sip_auth_username":"1001","sip_auth_realm":"192.168.56.74","number_alias":"1001","requested_domain_name":"192.168.56.66","record_stereo":"true","default_gateway":"example.com","default_areacode":"918","transfer_fallback_extension":"operator","toll_allow":"domestic,international,local","accountcode":"1001","user_context":"default","effective_caller_id_name":"Extension 1001","effective_caller_id_number":"1001","outbound_caller_id_name":"FreeSWITCH","outbound_caller_id_number":"0000000000","callgroup":"techsupport","user_name":"1001","domain_name":"192.168.56.66","sip_from_user_stripped":"1001","sofia_profile_name":"internal","recovery_profile_name":"internal","sip_req_user":"1002","sip_req_uri":"1002@192.168.56.74","sip_req_host":"192.168.56.74","sip_to_user":"1002","sip_to_uri":"1002@192.168.56.74","sip_to_host":"192.168.56.74","sip_contact_params":"transport=udp;registering_acc=192_168_56_74","sip_contact_user":"1001","sip_contact_port":"5060","sip_contact_uri":"1001@192.168.56.1:5060","sip_contact_host":"192.168.56.1","sip_via_host":"192.168.56.1","sip_via_port":"5060","presence_id":"1001@192.168.56.74","ep_codec_string":"G722@8000h@20i@64000b,PCMU@8000h@20i@64000b,PCMA@8000h@20i@64000b,GSM@8000h@20i@13200b","cgr_notify":"+AUTH_OK","max_forwards":"69","transfer_history":"1396984221:caefc538-5da4-4245-8716-112c706383d8:bl_xfer:1002/default/XML","transfer_source":"1396984221:caefc538-5da4-4245-8716-112c706383d8:bl_xfer:1002/default/XML","DP_MATCH":"ARRAY::1002|:1002","call_uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","RFC2822_DATE":"Tue, 08 Apr 2014 21:10:21 +0200","dialed_extension":"1002","export_vars":"RFC2822_DATE,RFC2822_DATE,dialed_extension","ringback":"%(2000,4000,440,480)","transfer_ringback":"local_stream://moh","call_timeout":"30","hangup_after_bridge":"true","continue_on_fail":"true","called_party_callgroup":"techsupport","current_application_data":"user/1002@192.168.56.66","current_application":"bridge","dialed_user":"1002","dialed_domain":"192.168.56.66","inherit_codec":"true","originated_legs":"ARRAY::402f0929-fa14-4a5f-9642-3a1311bb4ddd;Outbound Call;1002|:402f0929-fa14-4a5f-9642-3a1311bb4ddd;Outbound Call;1002","rtp_use_codec_string":"G722,PCMU,PCMA,GSM","sip_use_codec_name":"G722","sip_use_codec_rate":"8000","sip_use_codec_ptime":"20","write_codec":"G722","write_rate":"16000","video_possible":"true","local_media_ip":"192.168.56.74","local_media_port":"32534","advertised_media_ip":"192.168.56.74","sip_use_pt":"9","rtp_use_ssrc":"1431080133","zrtp_secure_media_confirmed_audio":"true","zrtp_sas1_string_audio":"j6ff","switch_m_sdp":"v=0\r\no=1002 0 0 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5020 RTP/AVP 9 0 8 3 101\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:101 telephone-event/8000\r\n","read_codec":"G722","read_rate":"16000","endpoint_disposition":"ANSWER","originate_causes":"ARRAY::402f0929-fa14-4a5f-9642-3a1311bb4ddd;NONE|:402f0929-fa14-4a5f-9642-3a1311bb4ddd;NONE","originate_disposition":"SUCCESS","DIALSTATUS":"SUCCESS","last_bridge_to":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","bridge_channel":"sofia/internal/sip:1002@192.168.56.1:5060","bridge_uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","signal_bond":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","last_sent_callee_id_name":"Outbound Call","last_sent_callee_id_number":"1002","cgr_RequestType":"*prepaid","sip_reinvite_sdp":"v=0\r\no=1001 0 1 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5016 RTP/AVP 96 97 98 9 100 102 0 8 103 3 104 101\r\na=sendonly\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 usedtx=1\r\na=rtpmap:97 SILK/24000\r\na=rtpmap:98 SILK/16000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:100 speex/32000\r\na=rtpmap:102 speex/16000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:103 iLBC/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:104 speex/8000\r\na=rtpmap:101 telephone-event/8000\r\na=extmap:1 urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=zrtp-hash:1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286\r\nm=video 0 RTP/AVP 105 99\r\n","switch_r_sdp":"v=0\r\no=1001 0 1 IN IP4 192.168.56.1\r\ns=-\r\nc=IN IP4 192.168.56.1\r\nt=0 0\r\nm=audio 5016 RTP/AVP 96 97 98 9 100 102 0 8 103 3 104 101\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 usedtx=1\r\na=rtpmap:97 SILK/24000\r\na=rtpmap:98 SILK/16000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:100 speex/32000\r\na=rtpmap:102 speex/16000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:103 iLBC/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:104 speex/8000\r\na=rtpmap:101 telephone-event/8000\r\na=sendonly\r\na=extmap:1 urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=zrtp-hash:1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286\r\nm=video 0 RTP/AVP 105 99\r\n","r_sdp_audio_zrtp_hash":"1.10 722d57097aaabea2749ea8938472478f8d88645b23521fa5f8005a7a2bed8286","remote_media_ip":"192.168.56.1","remote_media_port":"5016","sip_audio_recv_pt":"9","dtmf_type":"rfc2833","sip_2833_send_payload":"101","sip_2833_recv_payload":"101","sip_local_sdp_str":"v=0\no=FreeSWITCH 1396951687 1396951690 IN IP4 192.168.56.74\ns=FreeSWITCH\nc=IN IP4 192.168.56.74\nt=0 0\nm=audio 32534 RTP/AVP 9 101\na=rtpmap:9 G722/8000\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-16\na=ptime:20\na=sendrecv\n","sip_to_tag":"rXc9vZpv9eFaF","sip_from_tag":"1afc7eca","sip_cseq":"3","sip_call_id":"6691dbf8ffdc02bdacee02bc305d5c71@0:0:0:0:0:0:0:0","sip_full_via":"SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bK-323133-5d083abc0d3f327b9101586e71b5fce4","sip_from_display":"1001","sip_full_from":"\"1001\" ;tag=1afc7eca","sip_full_to":";tag=rXc9vZpv9eFaF","sip_term_status":"200","proto_specific_hangup_cause":"sip:200","sip_term_cause":"16","last_bridge_role":"originator","sip_user_agent":"Jitsi2.5.5065Linux","sip_hangup_disposition":"recv_bye","bridge_hangup_cause":"NORMAL_CLEARING","hangup_cause":"NORMAL_CLEARING","hangup_cause_q850":"16","digits_dialed":"none","start_stamp":"2014-04-08 21:10:21","profile_start_stamp":"2014-04-08 21:10:21","answer_stamp":"2014-04-08 21:10:27","bridge_stamp":"2014-04-08 21:10:27","hold_stamp":"2014-04-08 21:10:27","progress_stamp":"2014-04-08 21:10:21","progress_media_stamp":"2014-04-08 21:10:21","hold_events":"{{1396984227824182,1396984242247995}}","end_stamp":"2014-04-08 21:10:42","start_epoch":"1396984221","start_uepoch":"1396984221278217","profile_start_epoch":"1396984221","profile_start_uepoch":"1396984221377035","answer_epoch":"1396984227","answer_uepoch":"1396984227717006","bridge_epoch":"1396984227","bridge_uepoch":"1396984227737268","last_hold_epoch":"1396984227","last_hold_uepoch":"1396984227824167","hold_accum_seconds":"14","hold_accum_usec":"14423816","hold_accum_ms":"14423","resurrect_epoch":"0","resurrect_uepoch":"0","progress_epoch":"1396984221","progress_uepoch":"1396984221497331","progress_media_epoch":"1396984221","progress_media_uepoch":"1396984221517042","end_epoch":"1396984242","end_uepoch":"1396984242257026","last_app":"bridge","last_arg":"user/1002@192.168.56.66","caller_id":"\"1001\" <1001>","duration":"21","billsec":"15","progresssec":"0","answersec":"6","waitsec":"6","progress_mediasec":"0","flow_billsec":"21","mduration":"20979","billmsec":"14540","progressmsec":"219","answermsec":"6439","waitmsec":"6459","progress_mediamsec":"239","flow_billmsec":"20979","uduration":"20978809","billusec":"14540020","progressusec":"219114","answerusec":"6438789","waitusec":"6459051","progress_mediausec":"238825","flow_billusec":"20978809","rtp_audio_in_raw_bytes":"181360","rtp_audio_in_media_bytes":"180304","rtp_audio_in_packet_count":"1031","rtp_audio_in_media_packet_count":"1025","rtp_audio_in_skip_packet_count":"45","rtp_audio_in_jb_packet_count":"0","rtp_audio_in_dtmf_packet_count":"0","rtp_audio_in_cng_packet_count":"0","rtp_audio_in_flush_packet_count":"6","rtp_audio_in_largest_jb_size":"0","rtp_audio_out_raw_bytes":"165780","rtp_audio_out_media_bytes":"165780","rtp_audio_out_packet_count":"942","rtp_audio_out_media_packet_count":"942","rtp_audio_out_skip_packet_count":"0","rtp_audio_out_dtmf_packet_count":"0","rtp_audio_out_cng_packet_count":"0","rtp_audio_rtcp_packet_count":"0","rtp_audio_rtcp_octet_count":"0"},"app_log":{"applications":[{"app_name":"hash","app_data":"insert/192.168.56.66-spymap/1001/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/1001/1002"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"export","app_data":"RFC2822_DATE=Tue, 08 Apr 2014 21:10:21 +0200"},{"app_name":"park","app_data":""},{"app_name":"hash","app_data":"insert/192.168.56.66-spymap/1001/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/1001/1002"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"export","app_data":"RFC2822_DATE=Tue, 08 Apr 2014 21:10:21 +0200"},{"app_name":"export","app_data":"dialed_extension=1002"},{"app_name":"bind_meta_app","app_data":"1 b s execute_extension::dx XML features"},{"app_name":"bind_meta_app","app_data":"2 b s record_session::/var/lib/freeswitch/recordings/1001.2014-04-08-21-10-21.wav"},{"app_name":"bind_meta_app","app_data":"3 b s execute_extension::cf XML features"},{"app_name":"bind_meta_app","app_data":"4 b s execute_extension::att_xfer XML features"},{"app_name":"set","app_data":"ringback=%(2000,4000,440,480)"},{"app_name":"set","app_data":"transfer_ringback=local_stream://moh"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"set","app_data":"hangup_after_bridge=true"},{"app_name":"set","app_data":"continue_on_fail=true"},{"app_name":"hash","app_data":"insert/192.168.56.66-call_return/1002/1001"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/1002/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"set","app_data":"called_party_callgroup=techsupport"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/techsupport/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial_ext/global/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"hash","app_data":"insert/192.168.56.66-last_dial/techsupport/86cfd6e2-dbda-45a3-b59d-f683ec368e8b"},{"app_name":"bridge","app_data":"user/1002@192.168.56.66"}]},"callflow":{"dialplan":"XML","profile_index":"2","extension":{"name":"global","number":"1002","applications":[{"app_name":"hash","app_data":"insert/${domain_name}-spymap/${caller_id_number}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${caller_id_number}/${destination_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/global/${uuid}"},{"app_name":"export","app_data":"RFC2822_DATE=${strftime(%a, %d %b %Y %T %z)}"},{"app_name":"export","app_data":"dialed_extension=1002"},{"app_name":"bind_meta_app","app_data":"1 b s execute_extension::dx XML features"},{"app_name":"bind_meta_app","app_data":"2 b s record_session::/var/lib/freeswitch/recordings/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"},{"app_name":"bind_meta_app","app_data":"3 b s execute_extension::cf XML features"},{"app_name":"bind_meta_app","app_data":"4 b s execute_extension::att_xfer XML features"},{"app_name":"set","app_data":"ringback=${us-ring}"},{"app_name":"set","app_data":"transfer_ringback=local_stream://moh"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"set","app_data":"hangup_after_bridge=true"},{"app_name":"set","app_data":"continue_on_fail=true"},{"app_name":"hash","app_data":"insert/${domain_name}-call_return/${dialed_extension}/${caller_id_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/${dialed_extension}/${uuid}"},{"app_name":"set","app_data":"called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/${called_party_callgroup}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial_ext/global/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}"},{"app_name":"bridge","app_data":"user/${dialed_extension}@${domain_name}"},{"last_executed":"true","app_name":"answer","app_data":""},{"app_name":"sleep","app_data":"1000"},{"app_name":"bridge","app_data":"loopback/app=voicemail:default ${domain_name} ${dialed_extension}"}],"current_app":"answer"},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","source":"mod_sofia","context":"default","chan_name":"sofia/internal/1001@192.168.56.74","originatee":{"originatee_caller_profiles":[{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","source":"mod_sofia","context":"default","chan_name":"sofia/internal/sip:1002@192.168.56.1:5060"},{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"1002","destination_number":"1002","uuid":"402f0929-fa14-4a5f-9642-3a1311bb4ddd","source":"mod_sofia","context":"default","chan_name":"sofia/internal/sip:1002@192.168.56.1:5060"}]}},"times":{"created_time":"1396984221278217","profile_created_time":"1396984221377035","progress_time":"1396984221497331","progress_media_time":"1396984221517042","answered_time":"1396984227717006","hangup_time":"1396984242257026","resurrect_time":"0","transfer_time":"0"}},"callflow":{"dialplan":"XML","profile_index":"1","extension":{"name":"global","number":"1002","applications":[{"app_name":"hash","app_data":"insert/${domain_name}-spymap/${caller_id_number}/${uuid}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/${caller_id_number}/${destination_number}"},{"app_name":"hash","app_data":"insert/${domain_name}-last_dial/global/${uuid}"},{"app_name":"export","app_data":"RFC2822_DATE=${strftime(%a, %d %b %Y %T %z)}"},{"app_name":"park","app_data":""}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"192.168.56.1","rdnis":"","destination_number":"1002","uuid":"86cfd6e2-dbda-45a3-b59d-f683ec368e8b","source":"mod_sofia","context":"default","chan_name":"sofia/internal/1001@192.168.56.74"},"times":{"created_time":"1396984221278217","profile_created_time":"1396984221278217","progress_time":"0","progress_media_time":"0","answered_time":"0","hangup_time":"0","resurrect_time":"0","transfer_time":"1396984221377035"}}}`) func TestEvCorelate(t *testing.T) { answerEv := new(sessionmanager.FSEvent).AsEvent(answerEvent) @@ -222,11 +222,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("").AccId != "86cfd6e2-dbda-45a3-b59d-f683ec368e8b" { - t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").AccId) + } else if cdrEv.AsStoredCdr("").OriginID != "86cfd6e2-dbda-45a3-b59d-f683ec368e8b" { + t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").OriginID) } - if answerEv.GetCgrId("") != cdrEv.AsStoredCdr("").CgrId { - t.Error("CgrIds do not match", answerEv.GetCgrId(""), cdrEv.AsStoredCdr("").CgrId) + if answerEv.GetCgrId("") != cdrEv.AsStoredCdr("").CGRID { + t.Error("CGRIDs do not match", answerEv.GetCgrId(""), cdrEv.AsStoredCdr("").CGRID) } } @@ -372,7 +372,7 @@ variable_effective_caller_id_number: 1001 variable_outbound_caller_id_name: FreeSWITCH variable_outbound_caller_id_number: 0000000000 variable_callgroup: techsupport -variable_cgr_reqtype: *prepaid +variable_cgr_RequestType: *prepaid variable_cgr_supplier: supplier1 variable_user_name: 1001 variable_domain_name: cgrates.org @@ -540,7 +540,7 @@ variable_rtp_audio_out_cng_packet_count: 0 variable_rtp_audio_rtcp_packet_count: 1450 variable_rtp_audio_rtcp_octet_count: 45940` -var jsonCdr2 = []byte(`{"core-uuid":"651a8db2-4f67-4cf8-b622-169e8a482e50","switchname":"CgrDev1","channel_data":{"state":"CS_REPORTING","direction":"inbound","state_number":"11","flags":"0=1;1=1;37=1;38=1;40=1;43=1;48=1;53=1;105=1;111=1;112=1;116=1;118=1","caps":"1=1;2=1;3=1;4=1;5=1;6=1"},"variables":{"direction":"inbound","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","session_id":"4","sip_from_user":"1001","sip_from_uri":"1001@127.0.0.1","sip_from_host":"127.0.0.1","channel_name":"sofia/cgrtest/1001@127.0.0.1","ep_codec_string":"speex@16000h@20i,speex@8000h@20i,speex@32000h@20i,GSM@8000h@20i@13200b,PCMU@8000h@20i@64000b,PCMA@8000h@20i@64000b,G722@8000h@20i@64000b","sip_local_network_addr":"127.0.0.1","sip_network_ip":"127.0.0.1","sip_network_port":"46615","sip_received_ip":"127.0.0.1","sip_received_port":"46615","sip_via_protocol":"tcp","sip_authorized":"true","Event-Name":"REQUEST_PARAMS","Core-UUID":"651a8db2-4f67-4cf8-b622-169e8a482e50","FreeSWITCH-Hostname":"CgrDev1","FreeSWITCH-Switchname":"CgrDev1","FreeSWITCH-IPv4":"10.0.3.15","FreeSWITCH-IPv6":"::1","Event-Date-Local":"2015-07-07 16:52:08","Event-Date-GMT":"Tue, 07 Jul 2015 14:52:08 GMT","Event-Date-Timestamp":"1436280728471153","Event-Calling-File":"sofia.c","Event-Calling-Function":"sofia_handle_sip_i_invite","Event-Calling-Line-Number":"9056","Event-Sequence":"515","sip_number_alias":"1001","sip_auth_username":"1001","sip_auth_realm":"127.0.0.1","number_alias":"1001","requested_domain_name":"cgrates.org","record_stereo":"true","transfer_fallback_extension":"operator","toll_allow":"domestic,international,local","accountcode":"1001","user_context":"default","effective_caller_id_name":"Extension 1001","effective_caller_id_number":"1001","outbound_caller_id_name":"FreeSWITCH","outbound_caller_id_number":"0000000000","callgroup":"techsupport","cgr_reqtype":"*prepaid","cgr_supplier":"supplier1","user_name":"1001","domain_name":"cgrates.org","sip_from_user_stripped":"1001","sofia_profile_name":"cgrtest","recovery_profile_name":"cgrtest","sip_full_route":"","sip_recover_via":"SIP/2.0/TCP 127.0.0.1:46615;rport=46615;branch=z9hG4bKPjGj7AlihmVwAVz9McwVeI64NeBHlPmXAN;alias","sip_req_user":"1003","sip_req_uri":"1003@127.0.0.1","sip_req_host":"127.0.0.1","sip_to_user":"1003","sip_to_uri":"1003@127.0.0.1","sip_to_host":"127.0.0.1","sip_contact_params":"ob","sip_contact_user":"1001","sip_contact_port":"5072","sip_contact_uri":"1001@127.0.0.1:5072","sip_contact_host":"127.0.0.1","sip_via_host":"127.0.0.1","sip_via_port":"46615","sip_via_rport":"46615","switch_r_sdp":"v=0\r\no=- 3645269528 3645269528 IN IP4 10.0.3.15\r\ns=pjmedia\r\nb=AS:84\r\nt=0 0\r\na=X-nat:0\r\nm=audio 4006 RTP/AVP 98 97 99 104 3 0 8 9 96\r\nc=IN IP4 10.0.3.15\r\nb=AS:64000\r\na=rtpmap:98 speex/16000\r\na=rtpmap:97 speex/8000\r\na=rtpmap:99 speex/32000\r\na=rtpmap:104 iLBC/8000\r\na=fmtp:104 mode=30\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:96 telephone-event/8000\r\na=fmtp:96 0-16\r\na=rtcp:4007 IN IP4 10.0.3.15\r\n","rtp_remote_audio_rtcp_port":"4007 IN IP4 10.0.3.15","rtp_audio_recv_pt":"99","rtp_use_codec_name":"SPEEX","rtp_use_codec_rate":"32000","rtp_use_codec_ptime":"20","rtp_use_codec_channels":"1","rtp_last_audio_codec_string":"SPEEX@32000h@20i@1c","read_codec":"SPEEX","original_read_codec":"SPEEX","read_rate":"32000","original_read_rate":"32000","write_codec":"SPEEX","write_rate":"32000","dtmf_type":"rfc2833","execute_on_answer":"sched_hangup +3120 alloted_timeout","cgr_notify":"+AUTH_OK","max_forwards":"69","transfer_history":"1436280728:e7c250e8-6ad7-4bd4-8962-318e0b0da728:bl_xfer:1003/default/XML","transfer_source":"1436280728:e7c250e8-6ad7-4bd4-8962-318e0b0da728:bl_xfer:1003/default/XML","DP_MATCH":"ARRAY::1003|:1003","call_uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","ringback":"%(2000,4000,440,480)","call_timeout":"30","dialed_user":"1003","dialed_domain":"cgrates.org","originated_legs":"ARRAY::0a30dd7c-c222-482f-a322-b1218a15f8cd;Outbound Call;1003|:0a30dd7c-c222-482f-a322-b1218a15f8cd;Outbound Call;1003","switch_m_sdp":"v=0\r\no=- 3645269528 3645269529 IN IP4 10.0.3.15\r\ns=pjmedia\r\nb=AS:84\r\nt=0 0\r\na=X-nat:0\r\nm=audio 4018 RTP/AVP 99 101\r\nc=IN IP4 10.0.3.15\r\nb=AS:64000\r\na=rtpmap:99 speex/32000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-16\r\na=rtcp:4019 IN IP4 10.0.3.15\r\n","rtp_local_sdp_str":"v=0\no=FreeSWITCH 1436250882 1436250883 IN IP4 10.0.3.15\ns=FreeSWITCH\nc=IN IP4 10.0.3.15\nt=0 0\nm=audio 29846 RTP/AVP 99 96\na=rtpmap:99 speex/32000\na=rtpmap:96 telephone-event/8000\na=fmtp:96 0-16\na=ptime:20\na=sendrecv\na=rtcp:29847 IN IP4 10.0.3.15\n","local_media_ip":"10.0.3.15","local_media_port":"29846","advertised_media_ip":"10.0.3.15","rtp_use_pt":"99","rtp_use_ssrc":"1470667272","rtp_2833_send_payload":"96","rtp_2833_recv_payload":"96","remote_media_ip":"10.0.3.15","remote_media_port":"4006","endpoint_disposition":"ANSWER","current_application_data":"+3120 alloted_timeout","current_application":"sched_hangup","originate_causes":"ARRAY::0a30dd7c-c222-482f-a322-b1218a15f8cd;NONE|:0a30dd7c-c222-482f-a322-b1218a15f8cd;NONE","originate_disposition":"SUCCESS","DIALSTATUS":"SUCCESS","last_bridge_to":"0a30dd7c-c222-482f-a322-b1218a15f8cd","bridge_channel":"sofia/cgrtest/1003@127.0.0.1:5070","bridge_uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","signal_bond":"0a30dd7c-c222-482f-a322-b1218a15f8cd","sip_to_tag":"5Qt4ecvreSHZN","sip_from_tag":"YwuG8U3rRbqIn.xYTnU8NrI3giyxDBHJ","sip_cseq":"4178","sip_call_id":"r3xaJ8CLpyTAIHWUZG7gtZQYgAPEGf9S","sip_full_via":"SIP/2.0/UDP 10.0.3.15:5072;rport=5072;branch=z9hG4bKPjPqma7vnLxDkBqcCH3eXLmLYZoPS.6MDc;received=127.0.0.1","sip_full_from":"sip:1001@127.0.0.1;tag=YwuG8U3rRbqIn.xYTnU8NrI3giyxDBHJ","sip_full_to":"sip:1003@127.0.0.1;tag=5Qt4ecvreSHZN","last_sent_callee_id_name":"Outbound Call","last_sent_callee_id_number":"1003","sip_term_status":"200","proto_specific_hangup_cause":"sip:200","sip_term_cause":"16","last_bridge_role":"originator","sip_user_agent":"PJSUA v2.3 Linux-3.2.0.4/x86_64/glibc-2.13","sip_hangup_disposition":"recv_bye","bridge_hangup_cause":"NORMAL_CLEARING","hangup_cause":"NORMAL_CLEARING","hangup_cause_q850":"16","digits_dialed":"none","start_stamp":"2015-07-07 16:52:08","profile_start_stamp":"2015-07-07 16:52:08","answer_stamp":"2015-07-07 16:52:08","bridge_stamp":"2015-07-07 16:52:08","end_stamp":"2015-07-07 16:53:14","start_epoch":"1436280728","start_uepoch":"1436280728471153","profile_start_epoch":"1436280728","profile_start_uepoch":"1436280728930693","answer_epoch":"1436280728","answer_uepoch":"1436280728971147","bridge_epoch":"1436280728","bridge_uepoch":"1436280728971147","last_hold_epoch":"0","last_hold_uepoch":"0","hold_accum_seconds":"0","hold_accum_usec":"0","hold_accum_ms":"0","resurrect_epoch":"0","resurrect_uepoch":"0","progress_epoch":"0","progress_uepoch":"0","progress_media_epoch":"0","progress_media_uepoch":"0","end_epoch":"1436280794","end_uepoch":"1436280794010851","last_app":"sched_hangup","last_arg":"+3120 alloted_timeout","caller_id":"\"1001\" <1001>","duration":"66","billsec":"66","progresssec":"0","answersec":"0","waitsec":"0","progress_mediasec":"0","flow_billsec":"66","mduration":"65539","billmsec":"65039","progressmsec":"28","answermsec":"500","waitmsec":"500","progress_mediamsec":"28","flow_billmsec":"65539","uduration":"65539698","billusec":"65039704","progressusec":"0","answerusec":"499994","waitusec":"499994","progress_mediausec":"0","flow_billusec":"65539698","rtp_audio_in_raw_bytes":"6770","rtp_audio_in_media_bytes":"6762","rtp_audio_in_packet_count":"192","rtp_audio_in_media_packet_count":"190","rtp_audio_in_skip_packet_count":"6","rtp_audio_in_jitter_packet_count":"0","rtp_audio_in_dtmf_packet_count":"0","rtp_audio_in_cng_packet_count":"0","rtp_audio_in_flush_packet_count":"2","rtp_audio_in_largest_jb_size":"0","rtp_audio_in_jitter_min_variance":"26.73","rtp_audio_in_jitter_max_variance":"6716.71","rtp_audio_in_jitter_loss_rate":"0.00","rtp_audio_in_jitter_burst_rate":"0.00","rtp_audio_in_mean_interval":"36.67","rtp_audio_in_flaw_total":"0","rtp_audio_in_quality_percentage":"100.00","rtp_audio_in_mos":"4.50","rtp_audio_out_raw_bytes":"4686","rtp_audio_out_media_bytes":"4686","rtp_audio_out_packet_count":"108","rtp_audio_out_media_packet_count":"108","rtp_audio_out_skip_packet_count":"0","rtp_audio_out_dtmf_packet_count":"0","rtp_audio_out_cng_packet_count":"0","rtp_audio_rtcp_packet_count":"1450","rtp_audio_rtcp_octet_count":"45940"},"app_log":{"applications":[{"app_name":"info","app_data":""},{"app_name":"park","app_data":""},{"app_name":"info","app_data":""},{"app_name":"set","app_data":"ringback=%(2000,4000,440,480)"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"bridge","app_data":"user/1003@cgrates.org"},{"app_name":"sched_hangup","app_data":"+3120 alloted_timeout"}]},"callflow":{"dialplan":"XML","profile_index":"2","extension":{"name":"call_debug","number":"1003","applications":[{"app_name":"info","app_data":""},{"app_name":"set","app_data":"ringback=${us-ring}"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"bridge","app_data":"user/${destination_number}@${domain_name}"}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1001@127.0.0.1","originatee":{"originatee_caller_profiles":[{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1003@127.0.0.1:5070"},{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1003@127.0.0.1:5070"}]}},"times":{"created_time":"1436280728471153","profile_created_time":"1436280728930693","progress_time":"0","progress_media_time":"0","answered_time":"1436280728971147","bridged_time":"1436280728971147","last_hold_time":"0","hold_accum_time":"0","hangup_time":"1436280794010851","resurrect_time":"0","transfer_time":"0"}},"callflow":{"dialplan":"XML","profile_index":"1","extension":{"name":"call_debug","number":"1003","applications":[{"app_name":"info","app_data":""},{"app_name":"park","app_data":""}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"","destination_number":"1003","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1001@127.0.0.1"},"times":{"created_time":"1436280728471153","profile_created_time":"1436280728471153","progress_time":"0","progress_media_time":"0","answered_time":"0","bridged_time":"0","last_hold_time":"0","hold_accum_time":"0","hangup_time":"0","resurrect_time":"0","transfer_time":"1436280728930693"}}}`) +var jsonCdr2 = []byte(`{"core-uuid":"651a8db2-4f67-4cf8-b622-169e8a482e50","switchname":"CgrDev1","channel_data":{"state":"CS_REPORTING","direction":"inbound","state_number":"11","flags":"0=1;1=1;37=1;38=1;40=1;43=1;48=1;53=1;105=1;111=1;112=1;116=1;118=1","caps":"1=1;2=1;3=1;4=1;5=1;6=1"},"variables":{"direction":"inbound","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","session_id":"4","sip_from_user":"1001","sip_from_uri":"1001@127.0.0.1","sip_from_host":"127.0.0.1","channel_name":"sofia/cgrtest/1001@127.0.0.1","ep_codec_string":"speex@16000h@20i,speex@8000h@20i,speex@32000h@20i,GSM@8000h@20i@13200b,PCMU@8000h@20i@64000b,PCMA@8000h@20i@64000b,G722@8000h@20i@64000b","sip_local_network_addr":"127.0.0.1","sip_network_ip":"127.0.0.1","sip_network_port":"46615","sip_received_ip":"127.0.0.1","sip_received_port":"46615","sip_via_protocol":"tcp","sip_authorized":"true","Event-Name":"REQUEST_PARAMS","Core-UUID":"651a8db2-4f67-4cf8-b622-169e8a482e50","FreeSWITCH-Hostname":"CgrDev1","FreeSWITCH-Switchname":"CgrDev1","FreeSWITCH-IPv4":"10.0.3.15","FreeSWITCH-IPv6":"::1","Event-Date-Local":"2015-07-07 16:52:08","Event-Date-GMT":"Tue, 07 Jul 2015 14:52:08 GMT","Event-Date-Timestamp":"1436280728471153","Event-Calling-File":"sofia.c","Event-Calling-Function":"sofia_handle_sip_i_invite","Event-Calling-Line-Number":"9056","Event-Sequence":"515","sip_number_alias":"1001","sip_auth_username":"1001","sip_auth_realm":"127.0.0.1","number_alias":"1001","requested_domain_name":"cgrates.org","record_stereo":"true","transfer_fallback_extension":"operator","toll_allow":"domestic,international,local","accountcode":"1001","user_context":"default","effective_caller_id_name":"Extension 1001","effective_caller_id_number":"1001","outbound_caller_id_name":"FreeSWITCH","outbound_caller_id_number":"0000000000","callgroup":"techsupport","cgr_RequestType":"*prepaid","cgr_supplier":"supplier1","user_name":"1001","domain_name":"cgrates.org","sip_from_user_stripped":"1001","sofia_profile_name":"cgrtest","recovery_profile_name":"cgrtest","sip_full_route":"","sip_recover_via":"SIP/2.0/TCP 127.0.0.1:46615;rport=46615;branch=z9hG4bKPjGj7AlihmVwAVz9McwVeI64NeBHlPmXAN;alias","sip_req_user":"1003","sip_req_uri":"1003@127.0.0.1","sip_req_host":"127.0.0.1","sip_to_user":"1003","sip_to_uri":"1003@127.0.0.1","sip_to_host":"127.0.0.1","sip_contact_params":"ob","sip_contact_user":"1001","sip_contact_port":"5072","sip_contact_uri":"1001@127.0.0.1:5072","sip_contact_host":"127.0.0.1","sip_via_host":"127.0.0.1","sip_via_port":"46615","sip_via_rport":"46615","switch_r_sdp":"v=0\r\no=- 3645269528 3645269528 IN IP4 10.0.3.15\r\ns=pjmedia\r\nb=AS:84\r\nt=0 0\r\na=X-nat:0\r\nm=audio 4006 RTP/AVP 98 97 99 104 3 0 8 9 96\r\nc=IN IP4 10.0.3.15\r\nb=AS:64000\r\na=rtpmap:98 speex/16000\r\na=rtpmap:97 speex/8000\r\na=rtpmap:99 speex/32000\r\na=rtpmap:104 iLBC/8000\r\na=fmtp:104 mode=30\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:96 telephone-event/8000\r\na=fmtp:96 0-16\r\na=rtcp:4007 IN IP4 10.0.3.15\r\n","rtp_remote_audio_rtcp_port":"4007 IN IP4 10.0.3.15","rtp_audio_recv_pt":"99","rtp_use_codec_name":"SPEEX","rtp_use_codec_rate":"32000","rtp_use_codec_ptime":"20","rtp_use_codec_channels":"1","rtp_last_audio_codec_string":"SPEEX@32000h@20i@1c","read_codec":"SPEEX","original_read_codec":"SPEEX","read_rate":"32000","original_read_rate":"32000","write_codec":"SPEEX","write_rate":"32000","dtmf_type":"rfc2833","execute_on_answer":"sched_hangup +3120 alloted_timeout","cgr_notify":"+AUTH_OK","max_forwards":"69","transfer_history":"1436280728:e7c250e8-6ad7-4bd4-8962-318e0b0da728:bl_xfer:1003/default/XML","transfer_source":"1436280728:e7c250e8-6ad7-4bd4-8962-318e0b0da728:bl_xfer:1003/default/XML","DP_MATCH":"ARRAY::1003|:1003","call_uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","ringback":"%(2000,4000,440,480)","call_timeout":"30","dialed_user":"1003","dialed_domain":"cgrates.org","originated_legs":"ARRAY::0a30dd7c-c222-482f-a322-b1218a15f8cd;Outbound Call;1003|:0a30dd7c-c222-482f-a322-b1218a15f8cd;Outbound Call;1003","switch_m_sdp":"v=0\r\no=- 3645269528 3645269529 IN IP4 10.0.3.15\r\ns=pjmedia\r\nb=AS:84\r\nt=0 0\r\na=X-nat:0\r\nm=audio 4018 RTP/AVP 99 101\r\nc=IN IP4 10.0.3.15\r\nb=AS:64000\r\na=rtpmap:99 speex/32000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-16\r\na=rtcp:4019 IN IP4 10.0.3.15\r\n","rtp_local_sdp_str":"v=0\no=FreeSWITCH 1436250882 1436250883 IN IP4 10.0.3.15\ns=FreeSWITCH\nc=IN IP4 10.0.3.15\nt=0 0\nm=audio 29846 RTP/AVP 99 96\na=rtpmap:99 speex/32000\na=rtpmap:96 telephone-event/8000\na=fmtp:96 0-16\na=ptime:20\na=sendrecv\na=rtcp:29847 IN IP4 10.0.3.15\n","local_media_ip":"10.0.3.15","local_media_port":"29846","advertised_media_ip":"10.0.3.15","rtp_use_pt":"99","rtp_use_ssrc":"1470667272","rtp_2833_send_payload":"96","rtp_2833_recv_payload":"96","remote_media_ip":"10.0.3.15","remote_media_port":"4006","endpoint_disposition":"ANSWER","current_application_data":"+3120 alloted_timeout","current_application":"sched_hangup","originate_causes":"ARRAY::0a30dd7c-c222-482f-a322-b1218a15f8cd;NONE|:0a30dd7c-c222-482f-a322-b1218a15f8cd;NONE","originate_disposition":"SUCCESS","DIALSTATUS":"SUCCESS","last_bridge_to":"0a30dd7c-c222-482f-a322-b1218a15f8cd","bridge_channel":"sofia/cgrtest/1003@127.0.0.1:5070","bridge_uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","signal_bond":"0a30dd7c-c222-482f-a322-b1218a15f8cd","sip_to_tag":"5Qt4ecvreSHZN","sip_from_tag":"YwuG8U3rRbqIn.xYTnU8NrI3giyxDBHJ","sip_cseq":"4178","sip_call_id":"r3xaJ8CLpyTAIHWUZG7gtZQYgAPEGf9S","sip_full_via":"SIP/2.0/UDP 10.0.3.15:5072;rport=5072;branch=z9hG4bKPjPqma7vnLxDkBqcCH3eXLmLYZoPS.6MDc;received=127.0.0.1","sip_full_from":"sip:1001@127.0.0.1;tag=YwuG8U3rRbqIn.xYTnU8NrI3giyxDBHJ","sip_full_to":"sip:1003@127.0.0.1;tag=5Qt4ecvreSHZN","last_sent_callee_id_name":"Outbound Call","last_sent_callee_id_number":"1003","sip_term_status":"200","proto_specific_hangup_cause":"sip:200","sip_term_cause":"16","last_bridge_role":"originator","sip_user_agent":"PJSUA v2.3 Linux-3.2.0.4/x86_64/glibc-2.13","sip_hangup_disposition":"recv_bye","bridge_hangup_cause":"NORMAL_CLEARING","hangup_cause":"NORMAL_CLEARING","hangup_cause_q850":"16","digits_dialed":"none","start_stamp":"2015-07-07 16:52:08","profile_start_stamp":"2015-07-07 16:52:08","answer_stamp":"2015-07-07 16:52:08","bridge_stamp":"2015-07-07 16:52:08","end_stamp":"2015-07-07 16:53:14","start_epoch":"1436280728","start_uepoch":"1436280728471153","profile_start_epoch":"1436280728","profile_start_uepoch":"1436280728930693","answer_epoch":"1436280728","answer_uepoch":"1436280728971147","bridge_epoch":"1436280728","bridge_uepoch":"1436280728971147","last_hold_epoch":"0","last_hold_uepoch":"0","hold_accum_seconds":"0","hold_accum_usec":"0","hold_accum_ms":"0","resurrect_epoch":"0","resurrect_uepoch":"0","progress_epoch":"0","progress_uepoch":"0","progress_media_epoch":"0","progress_media_uepoch":"0","end_epoch":"1436280794","end_uepoch":"1436280794010851","last_app":"sched_hangup","last_arg":"+3120 alloted_timeout","caller_id":"\"1001\" <1001>","duration":"66","billsec":"66","progresssec":"0","answersec":"0","waitsec":"0","progress_mediasec":"0","flow_billsec":"66","mduration":"65539","billmsec":"65039","progressmsec":"28","answermsec":"500","waitmsec":"500","progress_mediamsec":"28","flow_billmsec":"65539","uduration":"65539698","billusec":"65039704","progressusec":"0","answerusec":"499994","waitusec":"499994","progress_mediausec":"0","flow_billusec":"65539698","rtp_audio_in_raw_bytes":"6770","rtp_audio_in_media_bytes":"6762","rtp_audio_in_packet_count":"192","rtp_audio_in_media_packet_count":"190","rtp_audio_in_skip_packet_count":"6","rtp_audio_in_jitter_packet_count":"0","rtp_audio_in_dtmf_packet_count":"0","rtp_audio_in_cng_packet_count":"0","rtp_audio_in_flush_packet_count":"2","rtp_audio_in_largest_jb_size":"0","rtp_audio_in_jitter_min_variance":"26.73","rtp_audio_in_jitter_max_variance":"6716.71","rtp_audio_in_jitter_loss_rate":"0.00","rtp_audio_in_jitter_burst_rate":"0.00","rtp_audio_in_mean_interval":"36.67","rtp_audio_in_flaw_total":"0","rtp_audio_in_quality_percentage":"100.00","rtp_audio_in_mos":"4.50","rtp_audio_out_raw_bytes":"4686","rtp_audio_out_media_bytes":"4686","rtp_audio_out_packet_count":"108","rtp_audio_out_media_packet_count":"108","rtp_audio_out_skip_packet_count":"0","rtp_audio_out_dtmf_packet_count":"0","rtp_audio_out_cng_packet_count":"0","rtp_audio_rtcp_packet_count":"1450","rtp_audio_rtcp_octet_count":"45940"},"app_log":{"applications":[{"app_name":"info","app_data":""},{"app_name":"park","app_data":""},{"app_name":"info","app_data":""},{"app_name":"set","app_data":"ringback=%(2000,4000,440,480)"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"bridge","app_data":"user/1003@cgrates.org"},{"app_name":"sched_hangup","app_data":"+3120 alloted_timeout"}]},"callflow":{"dialplan":"XML","profile_index":"2","extension":{"name":"call_debug","number":"1003","applications":[{"app_name":"info","app_data":""},{"app_name":"set","app_data":"ringback=${us-ring}"},{"app_name":"set","app_data":"call_timeout=30"},{"app_name":"bridge","app_data":"user/${destination_number}@${domain_name}"}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1001@127.0.0.1","originatee":{"originatee_caller_profiles":[{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1003@127.0.0.1:5070"},{"username":"1001","dialplan":"XML","caller_id_name":"Extension 1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"1003","destination_number":"1003","uuid":"0a30dd7c-c222-482f-a322-b1218a15f8cd","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1003@127.0.0.1:5070"}]}},"times":{"created_time":"1436280728471153","profile_created_time":"1436280728930693","progress_time":"0","progress_media_time":"0","answered_time":"1436280728971147","bridged_time":"1436280728971147","last_hold_time":"0","hold_accum_time":"0","hangup_time":"1436280794010851","resurrect_time":"0","transfer_time":"0"}},"callflow":{"dialplan":"XML","profile_index":"1","extension":{"name":"call_debug","number":"1003","applications":[{"app_name":"info","app_data":""},{"app_name":"park","app_data":""}]},"caller_profile":{"username":"1001","dialplan":"XML","caller_id_name":"1001","ani":"1001","aniii":"","caller_id_number":"1001","network_addr":"127.0.0.1","rdnis":"","destination_number":"1003","uuid":"e3133bf7-dcde-4daf-9663-9a79ffcef5ad","source":"mod_sofia","context":"default","chan_name":"sofia/cgrtest/1001@127.0.0.1"},"times":{"created_time":"1436280728471153","profile_created_time":"1436280728471153","progress_time":"0","progress_media_time":"0","answered_time":"0","bridged_time":"0","last_hold_time":"0","hold_accum_time":"0","hangup_time":"0","resurrect_time":"0","transfer_time":"1436280728930693"}}}`) // Make sure that both hangup and json cdr produce the same CGR primary fields func TestEvCdrCorelate(t *testing.T) { @@ -554,21 +554,21 @@ func TestEvCdrCorelate(t *testing.T) { cdrEv, err := engine.NewFSCdr(jsonCdr2, cfg) if err != nil { t.Errorf("Error loading cdr: %v", err.Error()) - } else if cdrEv.AsStoredCdr("").AccId != "e3133bf7-dcde-4daf-9663-9a79ffcef5ad" { - t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").AccId) + } else if cdrEv.AsStoredCdr("").OriginID != "e3133bf7-dcde-4daf-9663-9a79ffcef5ad" { + t.Error("Unexpected acntId received", cdrEv.AsStoredCdr("").OriginID) } jsnStoredCdr := cdrEv.AsStoredCdr("") - if evStoredCdr.CgrId != jsnStoredCdr.CgrId { - t.Errorf("evStoredCdr.CgrId: %s, jsnStoredCdr.CgrId: %s", evStoredCdr.CgrId, jsnStoredCdr.CgrId) + if evStoredCdr.CGRID != jsnStoredCdr.CGRID { + t.Errorf("evStoredCdr.CGRID: %s, jsnStoredCdr.CGRID: %s", evStoredCdr.CGRID, jsnStoredCdr.CGRID) } - if evStoredCdr.TOR != jsnStoredCdr.TOR { - t.Errorf("evStoredCdr.TOR: %s, jsnStoredCdr.TOR: %s", evStoredCdr.TOR, jsnStoredCdr.TOR) + if evStoredCdr.ToR != jsnStoredCdr.ToR { + t.Errorf("evStoredCdr.ToR: %s, jsnStoredCdr.ToR: %s", evStoredCdr.ToR, jsnStoredCdr.ToR) } - if evStoredCdr.AccId != jsnStoredCdr.AccId { - t.Errorf("evStoredCdr.AccId: %s, jsnStoredCdr.AccId: %s", evStoredCdr.AccId, jsnStoredCdr.AccId) + if evStoredCdr.OriginID != jsnStoredCdr.OriginID { + t.Errorf("evStoredCdr.OriginID: %s, jsnStoredCdr.OriginID: %s", evStoredCdr.OriginID, jsnStoredCdr.OriginID) } - if evStoredCdr.ReqType != jsnStoredCdr.ReqType { - t.Errorf("evStoredCdr.ReqType: %s, jsnStoredCdr.ReqType: %s", evStoredCdr.ReqType, jsnStoredCdr.ReqType) + 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) @@ -591,8 +591,8 @@ 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.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) diff --git a/general_tests/multiplecdrc_local_test.go b/general_tests/multiplecdrc_local_test.go index d0d704754..0d393554e 100644 --- a/general_tests/multiplecdrc_local_test.go +++ b/general_tests/multiplecdrc_local_test.go @@ -92,10 +92,8 @@ func TestMCDRCEmptyTables(t *testing.T) { t.Fatal("Error on mysql creation: ", err.Error()) return // No point in going further } - for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { - t.Fatal(err.Error()) - } + if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", utils.TBL_CDRS)); err != nil { + t.Fatal(err.Error()) } } diff --git a/general_tests/suretax_it_test.go b/general_tests/suretax_it_test.go index b5eacd153..43d9575c9 100644 --- a/general_tests/suretax_it_test.go +++ b/general_tests/suretax_it_test.go @@ -133,11 +133,11 @@ func TestSTIProcessExternalCdr(t *testing.T) { if !*testSureTax { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "teststicdr1", CdrHost: "192.168.1.1", CdrSource: "STI_TEST", ReqType: utils.META_RATED, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "teststicdr1", OriginHost: "192.168.1.1", Source: "STI_TEST", RequestType: utils.META_RATED, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "+14082342500", Destination: "+16268412300", Supplier: "SUPPL1", SetupTime: "2015-10-18T13:00:00Z", AnswerTime: "2015-10-18T13:00:00Z", - Usage: "15s", Pdd: "7.0", ExtraFields: map[string]string{"CustomerNumber": "000000534", "ZipCode": ""}, + Usage: "15s", PDD: "7.0", ExtraFields: map[string]string{"CustomerNumber": "000000534", "ZipCode": ""}, } var reply string if err := stiRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { @@ -152,8 +152,8 @@ func TestSTIGetCdrs(t *testing.T) { if !*testSureTax { return } - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}} if err := stiRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { @@ -163,7 +163,7 @@ func TestSTIGetCdrs(t *testing.T) { t.Errorf("Unexpected Cost for CDR: %+v", cdrs[0]) } } - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_SURETAX}, Accounts: []string{"1001"}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_SURETAX}, Accounts: []string{"1001"}} if err := stiRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { diff --git a/general_tests/tutorial_fs_calls_test.go b/general_tests/tutorial_fs_calls_test.go index 7d9494e5e..ae097294f 100644 --- a/general_tests/tutorial_fs_calls_test.go +++ b/general_tests/tutorial_fs_calls_test.go @@ -330,21 +330,21 @@ func TestTutFsCalls1001Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - var cgrId string // Share with getCostDetails + var reply []*engine.ExternalCDR + var CGRID string // Share with getCostDetails var cCost engine.CallCost - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1002"}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].CdrSource != "freeswitch_json" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + CGRID = reply[0].CGRID + if reply[0].Source != "freeswitch_json" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "67" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -357,21 +357,21 @@ func TestTutFsCalls1001Cdrs(t *testing.T) { //} } // Make sure call cost contains the matched information - if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil { + if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: CGRID}, &cCost); err != nil { t.Error("Unexpected error: ", err.Error()) } else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1003"}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + CGRID = reply[0].CGRID + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -381,19 +381,19 @@ func TestTutFsCalls1001Cdrs(t *testing.T) { } } // Make sure call cost contains the matched information - if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil { + if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: CGRID}, &cCost); err != nil { t.Error("Unexpected error: ", err.Error()) } else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true} + req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Subject != "1002" { t.Errorf("Unexpected Subject for CDR: %+v", reply[0]) @@ -407,18 +407,18 @@ func TestTutFsCalls1002Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { // Should be counted here also call originated form 1006 which is aliased to 1002 t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "freeswitch_json" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "freeswitch_json" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_POSTPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_POSTPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -434,18 +434,18 @@ func TestTutFsCalls1003Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "freeswitch_json" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "freeswitch_json" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PSEUDOPREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PSEUDOPREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -462,18 +462,18 @@ func TestTutFsCalls1004Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "freeswitch_json" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "freeswitch_json" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -490,8 +490,8 @@ func TestTutFsCalls1006Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 0 { @@ -504,18 +504,18 @@ func TestTutFsCalls1007Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "freeswitch_json" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "freeswitch_json" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1002" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) diff --git a/general_tests/tutorial_kam_calls_test.go b/general_tests/tutorial_kam_calls_test.go index c9f90885d..a724d6122 100644 --- a/general_tests/tutorial_kam_calls_test.go +++ b/general_tests/tutorial_kam_calls_test.go @@ -330,21 +330,21 @@ func TestTutKamCalls1001Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr + var reply []*engine.ExternalCDR var cgrId string // Share with getCostDetails var cCost engine.CallCost - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1002"}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + cgrId = reply[0].CGRID + if reply[0].Source != "KAMAILIO_CGR_CALL_END" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "67" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -363,15 +363,15 @@ func TestTutKamCalls1001Cdrs(t *testing.T) { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1003"}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + cgrId = reply[0].CGRID + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -386,14 +386,14 @@ func TestTutKamCalls1001Cdrs(t *testing.T) { } else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true} + req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Subject != "1002" { t.Errorf("Unexpected Subject for CDR: %+v", reply[0]) @@ -407,18 +407,18 @@ func TestTutKamCalls1002Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "KAMAILIO_CGR_CALL_END" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_POSTPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_POSTPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -434,18 +434,18 @@ func TestTutKamCalls1003Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "KAMAILIO_CGR_CALL_END" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PSEUDOPREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PSEUDOPREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -462,18 +462,18 @@ func TestTutKamCalls1004Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "KAMAILIO_CGR_CALL_END" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -490,8 +490,8 @@ func TestTutKamCalls1006Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 0 { @@ -504,18 +504,18 @@ func TestTutKamCalls1007Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "KAMAILIO_CGR_CALL_END" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1002" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) diff --git a/general_tests/tutorial_local_test.go b/general_tests/tutorial_local_test.go index db6e1d1c7..4bd82c70b 100644 --- a/general_tests/tutorial_local_test.go +++ b/general_tests/tutorial_local_test.go @@ -418,12 +418,12 @@ func TestTutLocalDerivedMaxSessionTime(t *testing.T) { return } tStart := time.Date(2014, 8, 4, 13, 0, 0, 0, time.UTC) - ev := engine.StoredCdr{ - CgrId: utils.Sha1("testevent1", tStart.String()), - TOR: utils.VOICE, - AccId: "testevent1", - CdrHost: "127.0.0.1", - ReqType: utils.META_PREPAID, + ev := engine.CDR{ + CGRID: utils.Sha1("testevent1", tStart.String()), + ToR: utils.VOICE, + OriginID: "testevent1", + OriginHost: "127.0.0.1", + RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", @@ -449,7 +449,7 @@ func TestTutLocalMaxUsage(t *testing.T) { if !*testLocal { return } - setupReq := &engine.UsageRecord{TOR: utils.VOICE, ReqType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -459,7 +459,7 @@ func TestTutLocalMaxUsage(t *testing.T) { } else if maxTime != 1 { t.Errorf("Calling ApierV2.MaxUsage got maxTime: %f", maxTime) } - setupReq = &engine.UsageRecord{TOR: utils.VOICE, ReqType: utils.META_RATED, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq = &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_RATED, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "test_max_usage", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", } @@ -475,7 +475,7 @@ func TestTutLocalDebitUsage(t *testing.T) { if !*testLocal { return } - setupReq := &engine.UsageRecord{TOR: utils.VOICE, ReqType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", + setupReq := &engine.UsageRecord{ToR: utils.VOICE, RequestType: utils.META_PREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", AnswerTime: "2014-08-04T13:00:00Z", Usage: "1", } @@ -492,11 +492,11 @@ func TestTutLocalProcessExternalCdr(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "testextcdr1", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + 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", 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", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { @@ -511,11 +511,11 @@ func TestTutLocalProcessExternalCdrUP(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "testextcdr2", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, Direction: utils.OUT, - ReqType: utils.USERS, Tenant: utils.USERS, Account: utils.USERS, Destination: "1001", Supplier: "SUPPL1", + 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", + Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": utils.USERS}, } var reply string @@ -524,32 +524,33 @@ func TestTutLocalProcessExternalCdrUP(t *testing.T) { } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } - eCdr := &engine.ExternalCdr{CgrId: "63a8d2bfeca2cfb790826c3ec461696d6574cfde", OrderId: 2, - TOR: utils.VOICE, - AccId: "testextcdr2", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + 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", - ExtraFields: map[string]string{"Cli": "+4986517174964", "fieldextr2": "valextr2", "SysUserName": "danb4"}, - MediationRunId: utils.DEFAULT_RUNID, Cost: 1} - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1004"}, DestPrefixes: []string{"1001"}} + Usage: "2", PDD: "0.2", DisconnectCause: "NORMAL_DISCONNECT", + 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"}} if err := tutLocalRpc.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].CgrId != eCdr.CgrId { - t.Errorf("Unexpected CgrId for CDR: %+v", cdrs[0]) + if cdrs[0].CGRID != eCdr.CGRID { + t.Errorf("Unexpected CGRID for CDR: %+v", cdrs[0]) } - if cdrs[0].TOR != eCdr.TOR { + if cdrs[0].ToR != eCdr.ToR { t.Errorf("Unexpected TOR for CDR: %+v", cdrs[0]) } - if cdrs[0].CdrSource != eCdr.CdrSource { - t.Errorf("Unexpected CdrSource for CDR: %+v", cdrs[0]) + if cdrs[0].Source != eCdr.Source { + t.Errorf("Unexpected Source for CDR: %+v", cdrs[0]) } - if cdrs[0].ReqType != eCdr.ReqType { - t.Errorf("Unexpected ReqType for CDR: %+v", cdrs[0]) + if cdrs[0].RequestType != eCdr.RequestType { + t.Errorf("Unexpected RequestType for CDR: %+v", cdrs[0]) } if cdrs[0].Tenant != eCdr.Tenant { t.Errorf("Unexpected Tenant for CDR: %+v", cdrs[0]) @@ -572,8 +573,8 @@ func TestTutLocalProcessExternalCdrUP(t *testing.T) { 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].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]) @@ -591,11 +592,11 @@ func TestTutLocalCostErrors(t *testing.T) { if !*testLocal { return } - cdr := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "testtutlocal_1", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: utils.OUT, + cdr := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "testtutlocal_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", 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", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } var reply string if err := tutLocalRpc.Call("CdrsV2.ProcessExternalCdr", cdr, &reply); err != nil { @@ -604,25 +605,25 @@ func TestTutLocalCostErrors(t *testing.T) { t.Error("Unexpected reply received: ", reply) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) - var cdrs []*engine.ExternalCdr - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{cdr.Account}, DestPrefixes: []string{cdr.Destination}} + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{cdr.Account}, DestinationPrefixes: []string{cdr.Destination}} if err := tutLocalRpc.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].AccId != cdr.AccId { - t.Errorf("Unexpected AccId for Cdr received: %+v", cdrs[0]) + if cdrs[0].OriginID != cdr.OriginID { + t.Errorf("Unexpected OriginID for Cdr received: %+v", cdrs[0]) } if cdrs[0].Cost != -1 { t.Errorf("Unexpected Cost for Cdr received: %+v", cdrs[0]) } } - cdr2 := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "testtutlocal_2", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, Direction: utils.OUT, + cdr2 := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "testtutlocal_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", 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", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV2.ProcessExternalCdr", cdr2, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -630,24 +631,24 @@ func TestTutLocalCostErrors(t *testing.T) { t.Error("Unexpected reply received: ", reply) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for CDR to be processed - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{cdr2.Account}, DestPrefixes: []string{cdr2.Destination}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{cdr2.Account}, DestinationPrefixes: []string{cdr2.Destination}} if err := tutLocalRpc.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].AccId != cdr2.AccId { - t.Errorf("Unexpected AccId for Cdr received: %+v", cdrs[0]) + if cdrs[0].OriginID != cdr2.OriginID { + t.Errorf("Unexpected OriginID for Cdr received: %+v", cdrs[0]) } if cdrs[0].Cost != -1 { t.Errorf("Unexpected Cost for Cdr received: %+v", cdrs[0]) } } - cdr3 := &engine.ExternalCdr{TOR: utils.VOICE, - AccId: "testtutlocal_3", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, Direction: utils.OUT, + cdr3 := &engine.ExternalCDR{ToR: utils.VOICE, + OriginID: "testtutlocal_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", 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", PDD: "7.0", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, } if err := tutLocalRpc.Call("CdrsV2.ProcessExternalCdr", cdr3, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) @@ -655,14 +656,14 @@ func TestTutLocalCostErrors(t *testing.T) { t.Error("Unexpected reply received: ", reply) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for CDR to be processed - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{cdr3.Account}, DestPrefixes: []string{cdr3.Destination}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{cdr3.Account}, DestinationPrefixes: []string{cdr3.Destination}} if err := tutLocalRpc.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].AccId != cdr3.AccId { - t.Errorf("Unexpected AccId for Cdr received: %+v", cdrs[0]) + if cdrs[0].OriginID != cdr3.OriginID { + t.Errorf("Unexpected OriginID for Cdr received: %+v", cdrs[0]) } if cdrs[0].Cost != -1 { t.Errorf("Unexpected Cost for Cdr received: %+v", cdrs[0]) @@ -822,20 +823,20 @@ func TestTutLocalLcrQos(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eStLcr.SupplierCosts[0], lcr.SupplierCosts[0]) } // Post some CDRs to influence stats - testCdr1 := &engine.StoredCdr{CgrId: utils.Sha1("testcdr1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "testcdr1", CdrHost: "192.168.1.1", CdrSource: "TEST_QOS_LCR", ReqType: utils.META_RATED, + 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", 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", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} - testCdr2 := &engine.StoredCdr{CgrId: utils.Sha1("testcdr2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "testcdr2", CdrHost: "192.168.1.1", CdrSource: "TEST_QOS_LCR", ReqType: utils.META_RATED, + 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", 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", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} var reply string - for _, cdr := range []*engine.StoredCdr{testCdr1, testCdr2} { + for _, cdr := range []*engine.CDR{testCdr1, testCdr2} { if err := tutLocalRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { @@ -860,8 +861,8 @@ func TestTutLocalLcrQos(t *testing.T) { //} else if !reflect.DeepEqual(eStLcr.SupplierCosts, lcr.SupplierCosts) && !reflect.DeepEqual(eStLcr2.SupplierCosts, lcr.SupplierCosts) { // t.Errorf("Expecting: %+v, %+v, received: %+v, %+v", eStLcr.SupplierCosts[0], eStLcr.SupplierCosts[1], lcr.SupplierCosts[0], lcr.SupplierCosts[1]) } - testCdr3 := &engine.StoredCdr{CgrId: utils.Sha1("testcdr3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "testcdr3", CdrHost: "192.168.1.1", CdrSource: "TEST_QOS_LCR", ReqType: utils.META_RATED, + 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", 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"} @@ -924,8 +925,8 @@ func TestTutLocalLcrQosThreshold(t *testing.T) { //} else if !reflect.DeepEqual(eLcr.SupplierCosts, lcr.SupplierCosts) { // t.Errorf("Expecting: %+v, %+v received: %+v, %+v", eLcr.SupplierCosts[0], eLcr.SupplierCosts[1], lcr.SupplierCosts[0], lcr.SupplierCosts[1]) } - testCdr4 := &engine.StoredCdr{CgrId: utils.Sha1("testcdr4", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "testcdr4", CdrHost: "192.168.1.1", CdrSource: "TEST_QOS_LCR", ReqType: utils.META_RATED, + 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", 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"} @@ -987,8 +988,8 @@ func TestTutLocalLcrQosThreshold(t *testing.T) { //} else if !reflect.DeepEqual(eLcr.SupplierCosts, lcr.SupplierCosts) && !reflect.DeepEqual(eLcr2.SupplierCosts, lcr.SupplierCosts) { // t.Errorf("Expecting: %+v, received: %+v", eLcr.SupplierCosts[1], lcr.SupplierCosts[1]) } - testCdr5 := &engine.StoredCdr{CgrId: utils.Sha1("testcdr5", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), - TOR: utils.VOICE, AccId: "testcdr5", CdrHost: "192.168.1.1", CdrSource: "TEST_QOS_LCR", ReqType: utils.META_RATED, + 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", 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"} diff --git a/general_tests/tutorial_osips_calls_test.go b/general_tests/tutorial_osips_calls_test.go index 2ee358950..30cb0590b 100644 --- a/general_tests/tutorial_osips_calls_test.go +++ b/general_tests/tutorial_osips_calls_test.go @@ -330,21 +330,21 @@ func TestTutOsipsCalls1001Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr + var reply []*engine.ExternalCDR var cgrId string // Share with getCostDetails var cCost engine.CallCost - req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1002"}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].CdrSource != "OSIPS_E_ACC_EVENT" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + cgrId = reply[0].CGRID + if reply[0].Source != "OSIPS_E_ACC_EVENT" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "67" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -363,15 +363,15 @@ func TestTutOsipsCalls1001Cdrs(t *testing.T) { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1003"}} + req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - cgrId = reply[0].CgrId - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + cgrId = reply[0].CGRID + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) @@ -386,14 +386,14 @@ func TestTutOsipsCalls1001Cdrs(t *testing.T) { } else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") { t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0]) } - req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true} + req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Subject != "1002" { t.Errorf("Unexpected Subject for CDR: %+v", reply[0]) @@ -407,18 +407,18 @@ func TestTutOsipsCalls1002Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 2 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "OSIPS_E_ACC_EVENT" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "OSIPS_E_ACC_EVENT" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_POSTPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_POSTPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -434,18 +434,18 @@ func TestTutOsipsCalls1003Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "OSIPS_E_ACC_EVENT" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "OSIPS_E_ACC_EVENT" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PSEUDOPREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PSEUDOPREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -462,18 +462,18 @@ func TestTutOsipsCalls1004Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "OSIPS_E_ACC_EVENT" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "OSIPS_E_ACC_EVENT" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_RATED { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_RATED { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) @@ -490,8 +490,8 @@ func TestTutOsipsCalls1006Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 0 { @@ -504,18 +504,18 @@ func TestTutOsipsCalls1007Cdrs(t *testing.T) { if !*testCalls { return } - var reply []*engine.ExternalCdr - req := utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}} + var reply []*engine.ExternalCDR + req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}} if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(reply) != 1 { t.Error("Unexpected number of CDRs returned: ", len(reply)) } else { - if reply[0].CdrSource != "OSIPS_E_ACC_EVENT" { - t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0]) + if reply[0].Source != "OSIPS_E_ACC_EVENT" { + t.Errorf("Unexpected Source for CDR: %+v", reply[0]) } - if reply[0].ReqType != utils.META_PREPAID { - t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) + if reply[0].RequestType != utils.META_PREPAID { + t.Errorf("Unexpected RequestType for CDR: %+v", reply[0]) } if reply[0].Destination != "1002" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) diff --git a/local_test.sh b/local_test.sh index b2089608c..b35a4e809 100755 --- a/local_test.sh +++ b/local_test.sh @@ -8,8 +8,8 @@ ap1=$? echo 'go test github.com/cgrates/cgrates/apier/v2 -local' go test github.com/cgrates/cgrates/apier/v2 -local ap2=$? -echo 'go test github.com/cgrates/cgrates/engine -local' -go test github.com/cgrates/cgrates/engine -local +echo 'go test github.com/cgrates/cgrates/engine -local -integration' +go test github.com/cgrates/cgrates/engine -local -integration en=$? echo 'go test github.com/cgrates/cgrates/cdrc -local' go test github.com/cgrates/cgrates/cdrc -local @@ -18,8 +18,10 @@ echo 'go test github.com/cgrates/cgrates/config -local' go test github.com/cgrates/cgrates/config -local cfg=$? echo 'go test github.com/cgrates/cgrates/utils -local' -echo 'go test github.com/cgrates/cgrates/general_tests -local' -go test github.com/cgrates/cgrates/general_tests -local +go test github.com/cgrates/cgrates/utils -local +utl=$? +echo 'go test github.com/cgrates/cgrates/general_tests -local -integration' +go test github.com/cgrates/cgrates/general_tests -local -integration gnr=$? echo 'go test github.com/cgrates/cgrates/agents -integration' go test github.com/cgrates/cgrates/agents -integration @@ -29,4 +31,4 @@ agts=$? -exit $gen && $ap1 && $ap2 && $en && $cdrc && $cfg && $gnr && $agts +exit $gen && $ap1 && $ap2 && $en && $cdrc && $cfg && $utl && $gnr && $agts diff --git a/sessionmanager/fsevent.go b/sessionmanager/fsevent.go index 905239d70..4ba9bdd4c 100644 --- a/sessionmanager/fsevent.go +++ b/sessionmanager/fsevent.go @@ -182,7 +182,7 @@ func (fsev FSEvent) MissingParameter(timezone string) bool { func (fsev FSEvent) GetSetupTime(fieldName, timezone string) (t time.Time, err error) { fsSTimeStr, hasKey := fsev[SETUP_TIME] if hasKey && fsSTimeStr != "0" { - // Discard the nanoseconds information since MySQL cannot store them in early versions and csv uses default seconds so cgrid will not corelate + // Discard the nanoseconds information since MySQL cannot store them in early versions and csv uses default seconds so CGRID will not corelate fsSTimeStr = fsSTimeStr[:len(fsSTimeStr)-6] } sTimeStr := utils.FirstNonEmpty(fsev[fieldName], fsSTimeStr) @@ -194,7 +194,7 @@ func (fsev FSEvent) GetSetupTime(fieldName, timezone string) (t time.Time, err e func (fsev FSEvent) GetAnswerTime(fieldName, timezone string) (t time.Time, err error) { fsATimeStr, hasKey := fsev[ANSWER_TIME] if hasKey && fsATimeStr != "0" { - // Discard the nanoseconds information since MySQL cannot store them in early versions and csv uses default seconds so cgrid will not corelate + // Discard the nanoseconds information since MySQL cannot store them in early versions and csv uses default seconds so CGRID will not corelate fsATimeStr = fsATimeStr[:len(fsATimeStr)-6] } aTimeStr := utils.FirstNonEmpty(fsev[fieldName], fsATimeStr) @@ -217,18 +217,18 @@ func (fsev FSEvent) GetDuration(fieldName string) (time.Duration, error) { } func (fsev FSEvent) GetPdd(fieldName string) (time.Duration, error) { - var pddStr string + var PDDStr string if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) { - pddStr = utils.FirstNonEmpty(fsev[PDD_MEDIA_MS], fsev[PDD_NOMEDIA_MS]) - if len(pddStr) != 0 { - pddStr = pddStr + "ms" // PDD is in milliseconds and CGR expects it in seconds + PDDStr = utils.FirstNonEmpty(fsev[PDD_MEDIA_MS], fsev[PDD_NOMEDIA_MS]) + if len(PDDStr) != 0 { + PDDStr = PDDStr + "ms" // PDD is in milliseconds and CGR expects it in seconds } } else if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value - pddStr = fieldName[len(utils.STATIC_VALUE_PREFIX):] + PDDStr = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { - pddStr = fsev[fieldName] + PDDStr = fsev[fieldName] } - return utils.ParseDurationWithSecs(pddStr) + return utils.ParseDurationWithSecs(PDDStr) } func (fsev FSEvent) GetSupplier(fieldName string) string { @@ -297,8 +297,8 @@ func (fsev FSEvent) ParseEventValue(rsrFld *utils.RSRField, timezone string) str dur, _ := fsev.GetDuration("") return rsrFld.ParseValue(strconv.FormatInt(dur.Nanoseconds(), 10)) case utils.PDD: - pdd, _ := fsev.GetPdd(utils.META_DEFAULT) - return rsrFld.ParseValue(strconv.FormatFloat(pdd.Seconds(), 'f', -1, 64)) + PDD, _ := fsev.GetPdd(utils.META_DEFAULT) + return rsrFld.ParseValue(strconv.FormatFloat(PDD.Seconds(), 'f', -1, 64)) case utils.SUPPLIER: return rsrFld.ParseValue(fsev.GetSupplier("")) case utils.DISCONNECT_CAUSE: @@ -337,14 +337,14 @@ func (fsev FSEvent) PassesFieldFilter(fieldFilter *utils.RSRField) (bool, string return false, "" } -func (fsev FSEvent) AsStoredCdr(timezone string) *engine.StoredCdr { - storCdr := new(engine.StoredCdr) - storCdr.CgrId = fsev.GetCgrId(timezone) - storCdr.TOR = utils.VOICE - storCdr.AccId = fsev.GetUUID() - storCdr.CdrHost = fsev.GetOriginatorIP(utils.META_DEFAULT) - storCdr.CdrSource = "FS_" + fsev.GetName() - storCdr.ReqType = fsev.GetReqType(utils.META_DEFAULT) +func (fsev FSEvent) AsStoredCdr(timezone string) *engine.CDR { + storCdr := new(engine.CDR) + storCdr.CGRID = fsev.GetCgrId(timezone) + storCdr.ToR = utils.VOICE + storCdr.OriginID = fsev.GetUUID() + 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) @@ -354,7 +354,7 @@ func (fsev FSEvent) AsStoredCdr(timezone string) *engine.StoredCdr { 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.PDD, _ = fsev.GetPdd(utils.META_DEFAULT) storCdr.ExtraFields = fsev.GetExtraFields() storCdr.Cost = -1 storCdr.Supplier = fsev.GetSupplier(utils.META_DEFAULT) diff --git a/sessionmanager/fsevent_test.go b/sessionmanager/fsevent_test.go index 30647505c..3dbb6c7e7 100644 --- a/sessionmanager/fsevent_test.go +++ b/sessionmanager/fsevent_test.go @@ -633,11 +633,12 @@ func TestFsEvAsStoredCdr(t *testing.T) { ev := new(FSEvent).AsEvent(hangupEv) setupTime, _ := utils.ParseTimeDetectLayout("1436280728", "") aTime, _ := utils.ParseTimeDetectLayout("1436280728", "") - eStoredCdr := &engine.StoredCdr{CgrId: "164b0422fdc6a5117031b427439482c6a4f90e41", - TOR: utils.VOICE, AccId: "e3133bf7-dcde-4daf-9663-9a79ffcef5ad", CdrHost: "10.0.3.15", CdrSource: "FS_CHANNEL_HANGUP_COMPLETE", ReqType: utils.META_PREPAID, + 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", 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, PDD: time.Duration(28) * time.Millisecond, Supplier: "supplier1", + DisconnectCause: "NORMAL_CLEARING", 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 bc7d7982c..3bd1bc215 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -296,10 +296,10 @@ func (sm *FSSessionManager) DisconnectSession(ev engine.Event, connId, notify st return nil } -func (sm *FSSessionManager) ProcessCdr(storedCdr *engine.StoredCdr) error { +func (sm *FSSessionManager) ProcessCdr(storedCdr *engine.CDR) error { var reply string if err := sm.cdrsrv.Call("CdrServer.ProcessCdr", storedCdr, &reply); err != nil { - utils.Logger.Err(fmt.Sprintf(" Failed processing CDR, cgrid: %s, accid: %s, error: <%s>", storedCdr.CgrId, storedCdr.AccId, err.Error())) + utils.Logger.Err(fmt.Sprintf(" Failed processing CDR, cgrid: %s, accid: %s, error: <%s>", storedCdr.CGRID, storedCdr.OriginID, err.Error())) } return nil } diff --git a/sessionmanager/kamailiosm.go b/sessionmanager/kamailiosm.go index 50034d7df..7d6dc3a15 100644 --- a/sessionmanager/kamailiosm.go +++ b/sessionmanager/kamailiosm.go @@ -205,13 +205,13 @@ func (self *KamailioSessionManager) Rater() rpcclient.RpcClientConnection { return self.rater } -func (self *KamailioSessionManager) ProcessCdr(cdr *engine.StoredCdr) error { +func (self *KamailioSessionManager) ProcessCdr(cdr *engine.CDR) error { if !self.cfg.CreateCdr { return nil } var reply string if err := self.cdrsrv.Call("CdrServer.ProcessCdr", cdr, &reply); err != nil { - utils.Logger.Err(fmt.Sprintf(" Failed processing CDR, cgrid: %s, accid: %s, error: <%s>", cdr.CgrId, cdr.AccId, err.Error())) + utils.Logger.Err(fmt.Sprintf(" Failed processing CDR, cgrid: %s, accid: %s, error: <%s>", cdr.CGRID, cdr.OriginID, err.Error())) } return nil } diff --git a/sessionmanager/kamevent.go b/sessionmanager/kamevent.go index 4c9fe9fde..422498c0f 100644 --- a/sessionmanager/kamevent.go +++ b/sessionmanager/kamevent.go @@ -316,14 +316,14 @@ func (kev KamEvent) PassesFieldFilter(*utils.RSRField) (bool, string) { return false, "" } -func (kev KamEvent) AsStoredCdr(timezone string) *engine.StoredCdr { - storCdr := new(engine.StoredCdr) - storCdr.CgrId = kev.GetCgrId(timezone) - storCdr.TOR = utils.VOICE - storCdr.AccId = kev.GetUUID() - storCdr.CdrHost = kev.GetOriginatorIP(utils.META_DEFAULT) - storCdr.CdrSource = kev.GetCdrSource() - storCdr.ReqType = kev.GetReqType(utils.META_DEFAULT) +func (kev KamEvent) AsStoredCdr(timezone string) *engine.CDR { + storCdr := new(engine.CDR) + storCdr.CGRID = kev.GetCgrId(timezone) + storCdr.ToR = utils.VOICE + storCdr.OriginID = kev.GetUUID() + 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) @@ -333,7 +333,7 @@ func (kev KamEvent) AsStoredCdr(timezone string) *engine.StoredCdr { 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.PDD, _ = kev.GetPdd(utils.META_DEFAULT) storCdr.Supplier = kev.GetSupplier(utils.META_DEFAULT) storCdr.DisconnectCause = kev.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = kev.GetExtraFields() diff --git a/sessionmanager/osipsevent.go b/sessionmanager/osipsevent.go index 42332eba0..cbb5052f9 100644 --- a/sessionmanager/osipsevent.go +++ b/sessionmanager/osipsevent.go @@ -264,14 +264,14 @@ func (osipsev *OsipsEvent) DialogId() string { return osipsev.osipsEvent.AttrValues[OSIPS_DIALOG_ID] } -func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.StoredCdr { - storCdr := new(engine.StoredCdr) - storCdr.CgrId = osipsEv.GetCgrId(timezone) - storCdr.TOR = utils.VOICE - storCdr.AccId = osipsEv.GetUUID() - storCdr.CdrHost = osipsEv.GetOriginatorIP(utils.META_DEFAULT) - storCdr.CdrSource = "OSIPS_" + osipsEv.GetName() - storCdr.ReqType = osipsEv.GetReqType(utils.META_DEFAULT) +func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.CDR { + storCdr := new(engine.CDR) + storCdr.CGRID = osipsEv.GetCgrId(timezone) + storCdr.ToR = utils.VOICE + storCdr.OriginID = osipsEv.GetUUID() + 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) @@ -281,7 +281,7 @@ func (osipsEv *OsipsEvent) AsStoredCdr(timezone string) *engine.StoredCdr { 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.PDD, _ = osipsEv.GetPdd(utils.META_DEFAULT) storCdr.Supplier = osipsEv.GetSupplier(utils.META_DEFAULT) storCdr.DisconnectCause = osipsEv.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = osipsEv.GetExtraFields() diff --git a/sessionmanager/osipsevent_test.go b/sessionmanager/osipsevent_test.go index 59b24c0e3..ac8c2b665 100644 --- a/sessionmanager/osipsevent_test.go +++ b/sessionmanager/osipsevent_test.go @@ -44,7 +44,7 @@ func TestOsipsEventParseStatic(t *testing.T) { setupTime, _ := osipsEv.GetSetupTime("^2013-12-07 08:42:24", "") answerTime, _ := osipsEv.GetAnswerTime("^2013-12-07 08:42:24", "") dur, _ := osipsEv.GetDuration("^60s") - pdd, _ := osipsEv.GetPdd("^10s") + PDD, _ := osipsEv.GetPdd("^10s") if osipsEv.GetReqType("^test") != "test" || osipsEv.GetDirection("^test") != "test" || osipsEv.GetTenant("^test") != "test" || @@ -55,7 +55,7 @@ func TestOsipsEventParseStatic(t *testing.T) { 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 || - pdd != time.Duration(10)*time.Second || + PDD != time.Duration(10)*time.Second || osipsEv.GetSupplier("^test") != "test" || osipsEv.GetDisconnectCause("^test") != "test" { t.Error("Values out of static not matching", @@ -69,7 +69,7 @@ func TestOsipsEventParseStatic(t *testing.T) { 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, - pdd != time.Duration(10)*time.Second, + PDD != time.Duration(10)*time.Second, osipsEv.GetSupplier("^test") != "test", osipsEv.GetDisconnectCause("^test") != "test") } @@ -83,7 +83,7 @@ func TestOsipsEventGetValues(t *testing.T) { answerTime, _ := osipsEv.GetAnswerTime(utils.META_DEFAULT, "") eAnswerTime, _ := utils.ParseTimeDetectLayout("1406370499", "") dur, _ := osipsEv.GetDuration(utils.META_DEFAULT) - pdd, _ := osipsEv.GetPdd(utils.META_DEFAULT) + PDD, _ := osipsEv.GetPdd(utils.META_DEFAULT) endTime, _ := osipsEv.GetEndTime(utils.META_DEFAULT, "") if osipsEv.GetName() != "E_ACC_CDR" || osipsEv.GetCgrId("") != utils.Sha1("ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", setupTime.UTC().String()) || @@ -100,7 +100,7 @@ func TestOsipsEventGetValues(t *testing.T) { !answerTime.Equal(eAnswerTime) || !endTime.Equal(eAnswerTime.Add(dur)) || dur != time.Duration(20*time.Second) || - pdd != time.Duration(3)*time.Second || + PDD != time.Duration(3)*time.Second || osipsEv.GetSupplier(utils.META_DEFAULT) != "supplier3" || osipsEv.GetDisconnectCause(utils.META_DEFAULT) != "200" || osipsEv.GetOriginatorIP(utils.META_DEFAULT) != "172.16.254.77" { @@ -119,7 +119,7 @@ func TestOsipsEventGetValues(t *testing.T) { !answerTime.Equal(time.Date(2014, 7, 26, 12, 28, 19, 0, time.Local)), !endTime.Equal(time.Date(2014, 7, 26, 12, 28, 39, 0, time.Local)), dur != time.Duration(20*time.Second), - pdd != time.Duration(3)*time.Second, + PDD != time.Duration(3)*time.Second, osipsEv.GetSupplier(utils.META_DEFAULT) != "supplier3", osipsEv.GetDisconnectCause(utils.META_DEFAULT) != "200", osipsEv.GetOriginatorIP(utils.META_DEFAULT) != "172.16.254.77", @@ -143,12 +143,12 @@ func TestOsipsEventMissingParameter(t *testing.T) { func TestOsipsEventAsStoredCdr(t *testing.T) { setupTime, _ := utils.ParseTimeDetectLayout("1406370492", "") answerTime, _ := utils.ParseTimeDetectLayout("1406370499", "") - eStoredCdr := &engine.StoredCdr{CgrId: utils.Sha1("ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", setupTime.UTC().String()), - TOR: utils.VOICE, AccId: "ODVkMDI2Mzc2MDY5N2EzODhjNTAzNTdlODhiZjRlYWQ", CdrHost: "172.16.254.77", CdrSource: "OSIPS_E_ACC_CDR", - ReqType: utils.META_PREPAID, - Direction: utils.OUT, Tenant: "itsyscom.com", Category: "call", Account: "dan", Subject: "dan", + 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", 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, PDD: time.Duration(3) * time.Second, Supplier: "supplier3", DisconnectCause: "200", 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) } @@ -162,9 +162,9 @@ func TestOsipsAccMissedToStoredCdr(t *testing.T) { "cgr_account": "1001", "cgr_destination": "1002", utils.CGR_SUPPLIER: "supplier1", "duration": "", "dialog_id": "3547:277000822", "extra1": "val1", "extra2": "val2"}, OriginatorAddress: addr, }} - eStoredCdr := &engine.StoredCdr{CgrId: utils.Sha1("27b1e6679ad0109b5d756e42bb4c9c28@0:0:0:0:0:0:0:0", setupTime.UTC().String()), - TOR: utils.VOICE, AccId: "27b1e6679ad0109b5d756e42bb4c9c28@0:0:0:0:0:0:0:0", CdrHost: "172.16.254.77", CdrSource: "OSIPS_E_ACC_MISSED_EVENT", - ReqType: utils.META_PSEUDOPREPAID, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Supplier: "supplier1", + 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, Usage: time.Duration(0), ExtraFields: map[string]string{"extra1": "val1", "extra2": "val2"}, Cost: -1} if storedCdr := osipsEv.AsStoredCdr(""); !reflect.DeepEqual(eStoredCdr, storedCdr) { diff --git a/sessionmanager/osipssm.go b/sessionmanager/osipssm.go index 86ffe40f7..de785188f 100644 --- a/sessionmanager/osipssm.go +++ b/sessionmanager/osipssm.go @@ -151,7 +151,7 @@ func (osm *OsipsSessionManager) Shutdown() error { } // Process the CDR with CDRS component -func (osm *OsipsSessionManager) ProcessCdr(storedCdr *engine.StoredCdr) error { +func (osm *OsipsSessionManager) ProcessCdr(storedCdr *engine.CDR) error { var reply string return osm.cdrsrv.Call("CdrServer.ProcessCdr", storedCdr, &reply) } diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 9320bd66e..30f36905c 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -40,7 +40,7 @@ type Session struct { func (s *Session) GetSessionRun(runid string) *engine.SessionRun { for _, sr := range s.sessionRuns { - if sr.DerivedCharger.RunId == runid { + if sr.DerivedCharger.RunID == runid { return sr } } @@ -237,7 +237,7 @@ func (s *Session) SaveOperations() { err := s.sessionManager.CdrSrv().Call("CdrServer.LogCallCost", &engine.CallCostLog{ CgrId: s.eventStart.GetCgrId(s.sessionManager.Timezone()), Source: utils.SESSION_MANAGER_SOURCE, - RunId: sr.DerivedCharger.RunId, + RunId: sr.DerivedCharger.RunID, CallCost: firstCC, CheckDuplicate: true, }, &reply) @@ -283,7 +283,7 @@ func (s *Session) AsActiveSessions() []*ActiveSession { SMId: "UNKNOWN", } if sessionRun.DerivedCharger != nil { - aSession.RunId = sessionRun.DerivedCharger.RunId + aSession.RunId = sessionRun.DerivedCharger.RunID } if sessionRun.CallDescriptor != nil { aSession.LoopIndex = sessionRun.CallDescriptor.LoopIndex diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 861b33768..c775c45a1 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -299,14 +299,14 @@ func (self SMGenericEvent) PassesFieldFilter(*utils.RSRField) (bool, string) { return true, "" } -func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) *engine.StoredCdr { - storCdr := engine.NewStoredCdrWithDefaults(cfg) - storCdr.CgrId = self.GetCgrId(timezone) - storCdr.TOR = utils.FirstNonEmpty(self.GetTOR(utils.META_DEFAULT), storCdr.TOR) // Keep default if none in the event - storCdr.AccId = self.GetUUID() - storCdr.CdrHost = self.GetOriginatorIP(utils.META_DEFAULT) - storCdr.CdrSource = self.GetCdrSource() - storCdr.ReqType = utils.FirstNonEmpty(self.GetReqType(utils.META_DEFAULT), storCdr.ReqType) +func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) *engine.CDR { + storCdr := engine.NewCDRWithDefaults(cfg) + storCdr.CGRID = self.GetCgrId(timezone) + storCdr.ToR = utils.FirstNonEmpty(self.GetTOR(utils.META_DEFAULT), storCdr.ToR) // Keep default if none in the event + storCdr.OriginID = self.GetUUID() + 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) @@ -316,7 +316,7 @@ 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.PDD, _ = self.GetPdd(utils.META_DEFAULT) storCdr.Supplier = self.GetSupplier(utils.META_DEFAULT) storCdr.DisconnectCause = self.GetDisconnectCause(utils.META_DEFAULT) storCdr.ExtraFields = self.GetExtraFields() diff --git a/sessionmanager/smg_event_test.go b/sessionmanager/smg_event_test.go index 055d3821a..a52503560 100644 --- a/sessionmanager/smg_event_test.go +++ b/sessionmanager/smg_event_test.go @@ -147,11 +147,11 @@ func TestSMGenericEventAsStoredCdr(t *testing.T) { smGev[utils.CDRHOST] = "10.0.3.15" smGev["Extra1"] = "Value1" smGev["Extra2"] = 5 - eStoredCdr := &engine.StoredCdr{CgrId: "0711eaa78e53937f1593dabc08c83ea04a915f2e", - TOR: utils.VOICE, AccId: "12345", CdrHost: "10.0.3.15", CdrSource: "SMG_TEST_EVENT", ReqType: utils.META_PREPAID, + eStoredCdr := &engine.CDR{CGRID: "0711eaa78e53937f1593dabc08c83ea04a915f2e", + ToR: utils.VOICE, 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", + Usage: time.Duration(83) * time.Second, PDD: time.Duration(300) * time.Millisecond, Supplier: "supplier1", DisconnectCause: "NORMAL_DISCONNECT", 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/smgeneric.go b/sessionmanager/smgeneric.go index b12cb7e9f..ede6f4b3f 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -91,7 +91,7 @@ func (self *SMGeneric) sessionStart(evStart SMGenericEvent, connId string) error } stopDebitChan := make(chan struct{}) for _, sessionRun := range sessionRuns { - s := &SMGSession{eventStart: evStart, connId: connId, runId: sessionRun.DerivedCharger.RunId, timezone: self.timezone, + s := &SMGSession{eventStart: evStart, connId: connId, runId: sessionRun.DerivedCharger.RunID, timezone: self.timezone, rater: self.rater, cdrsrv: self.cdrsrv, cd: sessionRun.CallDescriptor} self.indexSession(sessionId, s) if self.cgrCfg.SmGenericConfig.DebitInterval != 0 { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 65892955f..f4246bd3a 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -612,10 +612,8 @@ type AttrExpFileCdrs struct { Accounts []string // If provided, it will filter account Subjects []string // If provided, it will filter the rating subject DestinationPrefixes []string // If provided, it will filter on destination prefix - RatedAccounts []string // If provided, it will filter ratedaccount - RatedSubjects []string // If provided, it will filter the ratedsubject - OrderIdStart int64 // Export from this order identifier - OrderIdEnd int64 // Export smaller than this order identifier + OrderIdStart *int64 // Export from this order identifier + OrderIdEnd *int64 // Export smaller than this order identifier TimeStart string // If provided, it will represent the starting of the CDRs interval (>=) TimeEnd string // If provided, it will represent the end of the CDRs interval (<) SkipErrors bool // Do not export errored CDRs @@ -624,25 +622,23 @@ type AttrExpFileCdrs struct { Paginator } -func (self *AttrExpFileCdrs) AsCdrsFilter(timezone string) (*CdrsFilter, error) { - cdrFltr := &CdrsFilter{ - CgrIds: self.CgrIds, - RunIds: self.MediationRunIds, - Tors: self.TORs, - CdrHosts: self.CdrHosts, - CdrSources: self.CdrSources, - ReqTypes: self.ReqTypes, - Directions: self.Directions, - Tenants: self.Tenants, - Categories: self.Categories, - Accounts: self.Accounts, - Subjects: self.Subjects, - DestPrefixes: self.DestinationPrefixes, - RatedAccounts: self.RatedAccounts, - RatedSubjects: self.RatedSubjects, - OrderIdStart: self.OrderIdStart, - OrderIdEnd: self.OrderIdEnd, - Paginator: self.Paginator, +func (self *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) { + cdrFltr := &CDRsFilter{ + CGRIDs: self.CgrIds, + RunIDs: self.MediationRunIds, + ToRs: self.TORs, + OriginHosts: self.CdrHosts, + Sources: self.CdrSources, + RequestTypes: self.ReqTypes, + Directions: self.Directions, + Tenants: self.Tenants, + Categories: self.Categories, + Accounts: self.Accounts, + Subjects: self.Subjects, + DestinationPrefixes: self.DestinationPrefixes, + OrderIDStart: self.OrderIdStart, + OrderIDEnd: self.OrderIdEnd, + Paginator: self.Paginator, } if len(self.TimeStart) != 0 { if answerTimeStart, err := ParseTimeDetectLayout(self.TimeStart, timezone); err != nil { @@ -691,8 +687,8 @@ type AttrGetCdrs struct { DestinationPrefixes []string // If provided, it will filter on destination prefix RatedAccounts []string // If provided, it will filter ratedaccount RatedSubjects []string // If provided, it will filter the ratedsubject - OrderIdStart int64 // Export from this order identifier - OrderIdEnd int64 // Export smaller than this order identifier + OrderIdStart *int64 // Export from this order identifier + OrderIdEnd *int64 // Export smaller than this order identifier TimeStart string // If provided, it will represent the starting of the CDRs interval (>=) TimeEnd string // If provided, it will represent the end of the CDRs interval (<) SkipErrors bool // Do not export errored CDRs @@ -700,25 +696,23 @@ type AttrGetCdrs struct { Paginator } -func (self *AttrGetCdrs) AsCdrsFilter(timezone string) (*CdrsFilter, error) { - cdrFltr := &CdrsFilter{ - CgrIds: self.CgrIds, - RunIds: self.MediationRunIds, - Tors: self.TORs, - CdrHosts: self.CdrHosts, - CdrSources: self.CdrSources, - ReqTypes: self.ReqTypes, - Directions: self.Directions, - Tenants: self.Tenants, - Categories: self.Categories, - Accounts: self.Accounts, - Subjects: self.Subjects, - DestPrefixes: self.DestinationPrefixes, - RatedAccounts: self.RatedAccounts, - RatedSubjects: self.RatedSubjects, - OrderIdStart: self.OrderIdStart, - OrderIdEnd: self.OrderIdEnd, - Paginator: self.Paginator, +func (self *AttrGetCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) { + cdrFltr := &CDRsFilter{ + CGRIDs: self.CgrIds, + RunIDs: self.MediationRunIds, + ToRs: self.TORs, + OriginHosts: self.CdrHosts, + Sources: self.CdrSources, + RequestTypes: self.ReqTypes, + Directions: self.Directions, + Tenants: self.Tenants, + Categories: self.Categories, + Accounts: self.Accounts, + Subjects: self.Subjects, + DestinationPrefixes: self.DestinationPrefixes, + OrderIDStart: self.OrderIdStart, + OrderIDEnd: self.OrderIdEnd, + Paginator: self.Paginator, } if len(self.TimeStart) != 0 { if answerTimeStart, err := ParseTimeDetectLayout(self.TimeStart, timezone); err != nil { @@ -760,10 +754,8 @@ type AttrRateCdrs struct { Accounts []string // If provided, it will filter account Subjects []string // If provided, it will filter the rating subject DestinationPrefixes []string // If provided, it will filter on destination prefix - RatedAccounts []string // If provided, it will filter ratedaccount - RatedSubjects []string // If provided, it will filter the ratedsubject - OrderIdStart int64 // Export from this order identifier - OrderIdEnd int64 // Export smaller than this order identifier + OrderIdStart *int64 // Export from this order identifier + OrderIdEnd *int64 // Export smaller than this order identifier TimeStart string // If provided, it will represent the starting of the CDRs interval (>=) TimeEnd string // If provided, it will represent the end of the CDRs interval (<) RerateErrors bool // Rerate previous CDRs with errors (makes sense for reqtype rated and pseudoprepaid @@ -771,6 +763,44 @@ type AttrRateCdrs struct { SendToStats bool // Set to true if the CDRs should be sent to stats server } +func (attrRateCDRs *AttrRateCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) { + cdrFltr := &CDRsFilter{ + CGRIDs: attrRateCDRs.CgrIds, + RunIDs: attrRateCDRs.MediationRunIds, + OriginHosts: attrRateCDRs.CdrHosts, + Sources: attrRateCDRs.CdrSources, + ToRs: attrRateCDRs.TORs, + RequestTypes: attrRateCDRs.ReqTypes, + Directions: attrRateCDRs.Directions, + Tenants: attrRateCDRs.Tenants, + Categories: attrRateCDRs.Categories, + Accounts: attrRateCDRs.Accounts, + Subjects: attrRateCDRs.Subjects, + DestinationPrefixes: attrRateCDRs.DestinationPrefixes, + OrderIDStart: attrRateCDRs.OrderIdStart, + OrderIDEnd: attrRateCDRs.OrderIdEnd, + } + if aTime, err := ParseTimeDetectLayout(attrRateCDRs.TimeStart, timezone); err != nil { + return nil, err + } else if !aTime.IsZero() { + cdrFltr.AnswerTimeStart = &aTime + } + if aTimeEnd, err := ParseTimeDetectLayout(attrRateCDRs.TimeEnd, timezone); err != nil { + return nil, err + } else if !aTimeEnd.IsZero() { + cdrFltr.AnswerTimeEnd = &aTimeEnd + } + if attrRateCDRs.RerateErrors { + cdrFltr.MinCost = Float64Pointer(-1.0) + if !attrRateCDRs.RerateRated { + cdrFltr.MaxCost = Float64Pointer(0.0) + } + } else if attrRateCDRs.RerateRated { + cdrFltr.MinCost = Float64Pointer(0.0) + } + return cdrFltr, nil +} + type AttrLoadTpFromFolder struct { FolderPath string // Take files from folder absolute path DryRun bool // Do not write to database but parse only @@ -835,172 +865,158 @@ type ExportedTPStats struct { Compressed bool } -// Filter used in engine.GetStoredCdrs -type CdrsFilter struct { - CgrIds []string // If provided, it will filter based on the cgrids present in list - NotCgrIds []string // Filter specific CgrIds out - RunIds []string // If provided, it will filter on mediation runid - NotRunIds []string // Filter specific runIds out - Tors []string // If provided, filter on TypeOfRecord - NotTors []string // Filter specific TORs out - CdrHosts []string // If provided, it will filter cdrhost - NotCdrHosts []string // Filter out specific cdr hosts - CdrSources []string // If provided, it will filter cdrsource - NotCdrSources []string // Filter out specific CDR sources - ReqTypes []string // If provided, it will fiter reqtype - NotReqTypes []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 - NotCategories []string // Filter out specific categories - Accounts []string // If provided, it will filter account - NotAccounts []string // Filter out specific Accounts - Subjects []string // If provided, it will filter the rating subject - NotSubjects []string // Filter out specific subjects - DestPrefixes []string // If provided, it will filter on destination prefix - NotDestPrefixes []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 - RatedAccounts []string // If provided, it will filter ratedaccount - NotRatedAccounts []string // Filter out specific RatedAccounts - RatedSubjects []string // If provided, it will filter the ratedsubject - NotRatedSubjects []string // Filter out specific RatedSubjects - 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 - NotExtraFields map[string]string // Filter out based on extra fields content - OrderIdStart int64 // Export from this order identifier - OrderIdEnd int64 // Export smaller than this order identifier - SetupTimeStart *time.Time // Start of interval, bigger or equal than configured - SetupTimeEnd *time.Time // End interval, smaller than setupTime - AnswerTimeStart *time.Time // Start of interval, bigger or equal than configured - AnswerTimeEnd *time.Time // End interval, smaller than answerTime - CreatedAtStart *time.Time // Start of interval, bigger or equal than configured - CreatedAtEnd *time.Time // End interval, smaller than - UpdatedAtStart *time.Time // Start of interval, bigger or equal than configured - UpdatedAtEnd *time.Time // End interval, smaller than - MinUsage *float64 // Start of the usage interval (>=) - MaxUsage *float64 // End of the usage interval (<) - MinPdd *float64 // Start of the pdd interval (>=) - MaxPdd *float64 // End of the pdd interval (<) - MinCost *float64 // Start of the cost interval (>=) - MaxCost *float64 // End of the usage interval (<) - FilterOnRated bool // Do not consider rated CDRs but raw one - Unscoped bool // Include soft-deleted records in results - Count bool // If true count the items instead of returning data +// CDRsFilter is a filter used to get records out of storDB +type CDRsFilter struct { + CGRIDs []string // If provided, it will filter based on the cgrids present in list + NotCGRIDs []string // Filter specific CgrIds out + RunIDs []string // If provided, it will filter on mediation runid + NotRunIDs []string // Filter specific runIds out + OriginHosts []string // If provided, it will filter cdrhost + NotOriginHosts []string // Filter out specific cdr hosts + Sources []string // If provided, it will filter cdrsource + NotSources []string // Filter out specific CDR sources + ToRs []string // If provided, filter on TypeOfRecord + 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 + NotCategories []string // Filter out specific categories + Accounts []string // If provided, it will filter account + NotAccounts []string // Filter out specific Accounts + Subjects []string // If provided, it will filter the rating subject + 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 + NotExtraFields map[string]string // Filter out based on extra fields content + OrderIDStart *int64 // Export from this order identifier + OrderIDEnd *int64 // Export smaller than this order identifier + SetupTimeStart *time.Time // Start of interval, bigger or equal than configured + SetupTimeEnd *time.Time // End interval, smaller than setupTime + AnswerTimeStart *time.Time // Start of interval, bigger or equal than configured + AnswerTimeEnd *time.Time // End interval, smaller than answerTime + CreatedAtStart *time.Time // Start of interval, bigger or equal than configured + CreatedAtEnd *time.Time // End interval, smaller than + UpdatedAtStart *time.Time // Start of interval, bigger or equal than configured + 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 + Count bool // If true count the items instead of returning data Paginator } -// Used in Rpc calls, slightly different than CdrsFilter by using string instead of Time filters -type RpcCdrsFilter struct { - CgrIds []string // If provided, it will filter based on the cgrids present in list - NotCgrIds []string // Filter specific CgrIds out - RunIds []string // If provided, it will filter on mediation runid - NotRunIds []string // Filter specific runIds out - Tors []string // If provided, filter on TypeOfRecord - NotTors []string // Filter specific TORs out - CdrHosts []string // If provided, it will filter cdrhost - NotCdrHosts []string // Filter out specific cdr hosts - CdrSources []string // If provided, it will filter cdrsource - NotCdrSources []string // Filter out specific CDR sources - ReqTypes []string // If provided, it will fiter reqtype - NotReqTypes []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 - NotCategories []string // Filter out specific categories - Accounts []string // If provided, it will filter account - NotAccounts []string // Filter out specific Accounts - Subjects []string // If provided, it will filter the rating subject - NotSubjects []string // Filter out specific subjects - DestPrefixes []string // If provided, it will filter on destination prefix - NotDestPrefixes []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 - RatedAccounts []string // If provided, it will filter ratedaccount - NotRatedAccounts []string // Filter out specific RatedAccounts - RatedSubjects []string // If provided, it will filter the ratedsubject - NotRatedSubjects []string // Filter out specific RatedSubjects - 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 - NotExtraFields map[string]string // Filter out based on extra fields content - OrderIdStart int64 // Export from this order identifier - OrderIdEnd int64 // Export smaller than this order identifier - SetupTimeStart string // Start of interval, bigger or equal than configured - SetupTimeEnd string // End interval, smaller than setupTime - AnswerTimeStart string // Start of interval, bigger or equal than configured - AnswerTimeEnd string // End interval, smaller than answerTime - CreatedAtStart string // Start of interval, bigger or equal than configured - CreatedAtEnd string // End interval, smaller than - UpdatedAtStart string // Start of interval, bigger or equal than configured - UpdatedAtEnd string // End interval, smaller than - MinUsage *float64 // Start of the usage interval (>=) - MaxUsage *float64 // End of the usage interval (<) - MinPdd *float64 // Start of the pdd interval (>=) - MaxPdd *float64 // End of the pdd interval (<) - MinCost *float64 // Start of the cost interval (>=) - MaxCost *float64 // End of the usage interval (<) - FilterOnRated bool // Do not consider derived CDRs but original one - Paginator // Add pagination +// RPCCDRsFilter is a filter used in Rpc calls +// RPCCDRsFilter is slightly different than CDRsFilter by using string instead of Time filters +type RPCCDRsFilter struct { + CGRIDs []string // If provided, it will filter based on the cgrids present in list + NotCGRIDs []string // Filter specific CgrIds out + RunIDs []string // If provided, it will filter on mediation runid + NotRunIDs []string // Filter specific runIds out + OriginHosts []string // If provided, it will filter cdrhost + NotOriginHosts []string // Filter out specific cdr hosts + Sources []string // If provided, it will filter cdrsource + NotSources []string // Filter out specific CDR sources + ToRs []string // If provided, filter on TypeOfRecord + 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 + NotCategories []string // Filter out specific categories + Accounts []string // If provided, it will filter account + NotAccounts []string // Filter out specific Accounts + Subjects []string // If provided, it will filter the rating subject + 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 + NotExtraFields map[string]string // Filter out based on extra fields content + OrderIDStart *int64 // Export from this order identifier + OrderIDEnd *int64 // Export smaller than this order identifier + SetupTimeStart string // Start of interval, bigger or equal than configured + SetupTimeEnd string // End interval, smaller than setupTime + AnswerTimeStart string // Start of interval, bigger or equal than configured + AnswerTimeEnd string // End interval, smaller than answerTime + CreatedAtStart string // Start of interval, bigger or equal than configured + CreatedAtEnd string // End interval, smaller than + UpdatedAtStart string // Start of interval, bigger or equal than configured + 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 } -func (self *RpcCdrsFilter) AsCdrsFilter(timezone string) (*CdrsFilter, error) { - cdrFltr := &CdrsFilter{ - CgrIds: self.CgrIds, - NotCgrIds: self.NotCgrIds, - RunIds: self.RunIds, - NotRunIds: self.NotRunIds, - Tors: self.Tors, - NotTors: self.NotTors, - CdrHosts: self.CdrHosts, - NotCdrHosts: self.NotCdrHosts, - CdrSources: self.CdrSources, - NotCdrSources: self.NotCdrSources, - ReqTypes: self.ReqTypes, - NotReqTypes: self.NotReqTypes, - Directions: self.Directions, - NotDirections: self.NotDirections, - Tenants: self.Tenants, - NotTenants: self.NotTenants, - Categories: self.Categories, - NotCategories: self.NotCategories, - Accounts: self.Accounts, - NotAccounts: self.NotAccounts, - Subjects: self.Subjects, - NotSubjects: self.NotSubjects, - DestPrefixes: self.DestPrefixes, - NotDestPrefixes: self.NotDestPrefixes, - Suppliers: self.Suppliers, - NotSuppliers: self.NotSuppliers, - DisconnectCauses: self.DisconnectCauses, - NotDisconnectCauses: self.NotDisconnectCauses, - RatedAccounts: self.RatedAccounts, - NotRatedAccounts: self.NotRatedAccounts, - RatedSubjects: self.RatedSubjects, - NotRatedSubjects: self.NotRatedSubjects, - 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, - FilterOnRated: self.FilterOnRated, - Paginator: self.Paginator, +func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) { + cdrFltr := &CDRsFilter{ + CGRIDs: self.CGRIDs, + NotCGRIDs: self.NotCGRIDs, + RunIDs: self.RunIDs, + NotRunIDs: self.NotRunIDs, + ToRs: self.ToRs, + NotToRs: self.NotToRs, + OriginHosts: self.OriginHosts, + NotOriginHosts: self.NotOriginHosts, + Sources: self.Sources, + NotSources: self.NotSources, + RequestTypes: self.RequestTypes, + NotRequestTypes: self.NotRequestTypes, + Directions: self.Directions, + NotDirections: self.NotDirections, + Tenants: self.Tenants, + NotTenants: self.NotTenants, + Categories: self.Categories, + NotCategories: self.NotCategories, + Accounts: self.Accounts, + NotAccounts: self.NotAccounts, + Subjects: self.Subjects, + 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, } if len(self.SetupTimeStart) != 0 { if sTimeStart, err := ParseTimeDetectLayout(self.SetupTimeStart, timezone); err != nil { @@ -1064,20 +1080,20 @@ func (self *RpcCdrsFilter) AsCdrsFilter(timezone string) (*CdrsFilter, error) { type AttrExportCdrsToFile struct { CdrFormat *string // Cdr output file format FieldSeparator *string // Separator used between fields - ExportId *string // Optional exportid - ExportDir *string // If provided it overwrites the configured export directory + ExportID *string // Optional exportid + ExportFolder *string // If provided it overwrites the configured export directory ExportFileName *string // If provided the output filename will be set to this ExportTemplate *string // Exported fields template <""|fld1,fld2|*xml:instance_name> DataUsageMultiplyFactor *float64 // Multiply data usage before export (eg: convert from KBytes to Bytes) - SmsUsageMultiplyFactor *float64 // Multiply sms usage before export (eg: convert from SMS unit to call duration for some billing systems) + SMSUsageMultiplyFactor *float64 // Multiply sms usage before export (eg: convert from SMS unit to call duration for some billing systems) GenericUsageMultiplyFactor *float64 // Multiply generic usage before export (eg: convert from GENERIC unit to call duration for some billing systems) CostMultiplyFactor *float64 // Multiply the cost before export, eg: apply VAT CostShiftDigits *int // If defined it will shift cost digits before applying rouding (eg: convert from Eur->cents), -1 to use general config ones RoundDecimals *int // Overwrite configured roundDecimals with this dynamically, -1 to use general config ones - MaskDestinationId *string // Overwrite configured MaskDestId + MaskDestinationID *string // Overwrite configured MaskDestId MaskLength *int // Overwrite configured MaskLength, -1 to use general config ones - SuppressCgrIds bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds - RpcCdrsFilter // Inherit the CDR filter attributes + Verbose bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds + RPCCDRsFilter // Inherit the CDR filter attributes } type AttrSetActions struct { diff --git a/utils/consts.go b/utils/consts.go index caff839a2..a78f97e88 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -66,10 +66,8 @@ const ( TBL_TP_DERIVED_CHARGERS = "tp_derived_chargers" TBL_TP_USERS = "tp_users" TBL_TP_ALIASES = "tp_aliases" - TBL_CDRS_PRIMARY = "cdrs_primary" - TBL_CDRS_EXTRA = "cdrs_extra" - TBL_COST_DETAILS = "cost_details" - TBL_RATED_CDRS = "rated_cdrs" + TBLSMCosts = "sm_costs" + TBL_CDRS = "cdrs" TIMINGS_CSV = "Timings.csv" DESTINATIONS_CSV = "Destinations.csv" RATES_CSV = "Rates.csv" @@ -105,13 +103,13 @@ const ( GOB = "gob" MSGPACK = "msgpack" CSV_LOAD = "CSVLOAD" - CGRID = "CgrId" - TOR = "TOR" - ORDERID = "OrderId" - ACCID = "AccId" - CDRHOST = "CdrHost" - CDRSOURCE = "CdrSource" - REQTYPE = "ReqType" + CGRID = "CGRID" + TOR = "ToR" + ORDERID = "OrderID" + ACCID = "OriginID" + CDRSOURCE = "Source" + CDRHOST = "OriginHost" + REQTYPE = "RequestType" DIRECTION = "Direction" TENANT = "Tenant" CATEGORY = "Category" @@ -121,11 +119,9 @@ const ( SETUP_TIME = "SetupTime" ANSWER_TIME = "AnswerTime" USAGE = "Usage" - PDD = "Pdd" + PDD = "PDD" SUPPLIER = "Supplier" - MEDI_RUNID = "MediationRunId" - RATED_ACCOUNT = "RatedAccount" - RATED_SUBJECT = "RatedSubject" + MEDI_RUNID = "RunID" COST = "Cost" COST_DETAILS = "CostDetails" RATED = "rated" @@ -260,10 +256,13 @@ const ( MatchEndPrefix = "$" SMG = "SMG" MetaGrouped = "*grouped" + MetaRaw = "*raw" + CreatedAt = "CreatedAt" + UpdatedAt = "UpdatedAt" ) var ( CdreCdrFormats = []string{CSV, DRYRUN, CDRE_FIXED_WIDTH} - PrimaryCdrFields = []string{CGRID, TOR, ACCID, CDRHOST, CDRSOURCE, REQTYPE, DIRECTION, TENANT, CATEGORY, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, PDD, ANSWER_TIME, USAGE, + PrimaryCdrFields = []string{CGRID, CDRSOURCE, CDRHOST, ACCID, TOR, REQTYPE, DIRECTION, TENANT, CATEGORY, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, PDD, ANSWER_TIME, USAGE, SUPPLIER, DISCONNECT_CAUSE, COST, RATED} ) diff --git a/utils/derivedchargers.go b/utils/derivedchargers.go index 5d9d8def8..8496947f3 100644 --- a/utils/derivedchargers.go +++ b/utils/derivedchargers.go @@ -29,16 +29,16 @@ func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, if len(runId) == 0 { return nil, errors.New("Empty run id field") } - dc = &DerivedCharger{RunId: runId} + dc = &DerivedCharger{RunID: runId} dc.RunFilters = runFilters if strings.HasPrefix(dc.RunFilters, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilters, STATIC_VALUE_PREFIX) { if dc.rsrRunFilters, err = ParseRSRFields(dc.RunFilters, INFIELD_SEP); err != nil { return nil, err } } - dc.ReqTypeField = reqTypeFld - if strings.HasPrefix(dc.ReqTypeField, REGEXP_PREFIX) || strings.HasPrefix(dc.ReqTypeField, STATIC_VALUE_PREFIX) { - if dc.rsrReqTypeField, err = NewRSRField(dc.ReqTypeField); err != nil { + dc.RequestTypeField = reqTypeFld + if strings.HasPrefix(dc.RequestTypeField, REGEXP_PREFIX) || strings.HasPrefix(dc.RequestTypeField, STATIC_VALUE_PREFIX) { + if dc.rsrRequestTypeField, err = NewRSRField(dc.RequestTypeField); err != nil { return nil, err } } @@ -84,9 +84,9 @@ func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, return nil, err } } - dc.PddField = pddFld - if strings.HasPrefix(dc.PddField, REGEXP_PREFIX) || strings.HasPrefix(dc.PddField, STATIC_VALUE_PREFIX) { - if dc.rsrPddField, err = NewRSRField(dc.PddField); err != nil { + dc.PDDField = pddFld + if strings.HasPrefix(dc.PDDField, REGEXP_PREFIX) || strings.HasPrefix(dc.PDDField, STATIC_VALUE_PREFIX) { + if dc.rsrPddField, err = NewRSRField(dc.PDDField); err != nil { return nil, err } } @@ -130,9 +130,9 @@ func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, } type DerivedCharger struct { - RunId string // Unique runId in the chain + RunID string // Unique runId in the chain RunFilters string // Only run the charger if all the filters match - ReqTypeField string // Field containing request type info, number in case of csv source, '^' as prefix in case of static values + RequestTypeField string // Field containing request type info, number in case of csv source, '^' as prefix in case of static values DirectionField string // Field containing direction info TenantField string // Field containing tenant info CategoryField string // Field containing tor info @@ -140,7 +140,7 @@ type DerivedCharger struct { SubjectField string // Field containing subject information DestinationField string // Field containing destination information SetupTimeField string // Field containing setup time information - PddField string // Field containing setup time information + PDDField string // Field containing setup time information AnswerTimeField string // Field containing answer time information UsageField string // Field containing usage information SupplierField string // Field containing supplier information @@ -148,7 +148,7 @@ type DerivedCharger struct { CostField string // Field containing cost information RatedField string // Field marking rated request in CDR rsrRunFilters []*RSRField // Storage for compiled Regexp in case of RSRFields - rsrReqTypeField *RSRField + rsrRequestTypeField *RSRField rsrDirectionField *RSRField rsrTenantField *RSRField rsrCategoryField *RSRField @@ -166,9 +166,9 @@ type DerivedCharger struct { } func (dc *DerivedCharger) Equal(other *DerivedCharger) bool { - return dc.RunId == other.RunId && + return dc.RunID == other.RunID && dc.RunFilters == other.RunFilters && - dc.ReqTypeField == other.ReqTypeField && + dc.RequestTypeField == other.RequestTypeField && dc.DirectionField == other.DirectionField && dc.TenantField == other.TenantField && dc.CategoryField == other.CategoryField && @@ -176,7 +176,7 @@ func (dc *DerivedCharger) Equal(other *DerivedCharger) bool { dc.SubjectField == other.SubjectField && dc.DestinationField == other.DestinationField && dc.SetupTimeField == other.SetupTimeField && - dc.PddField == other.PddField && + dc.PDDField == other.PDDField && dc.AnswerTimeField == other.AnswerTimeField && dc.UsageField == other.UsageField && dc.SupplierField == other.SupplierField && @@ -190,17 +190,17 @@ func DerivedChargersKey(direction, tenant, category, account, subject string) st } type DerivedChargers struct { - DestinationIds StringMap + DestinationIDs StringMap Chargers []*DerivedCharger } // Precheck that RunId is unique func (dcs *DerivedChargers) Append(dc *DerivedCharger) (*DerivedChargers, error) { - if dc.RunId == DEFAULT_RUNID { + if dc.RunID == DEFAULT_RUNID { return nil, errors.New("Reserved RunId") } for _, dcLocal := range dcs.Chargers { - if dcLocal.RunId == dc.RunId { + if dcLocal.RunID == dc.RunID { return nil, errors.New("Duplicated RunId") } } @@ -216,7 +216,7 @@ func (dcs *DerivedChargers) AppendDefaultRun() (*DerivedChargers, error) { } func (dcs *DerivedChargers) Equal(other *DerivedChargers) bool { - dcs.DestinationIds.Equal(other.DestinationIds) + dcs.DestinationIDs.Equal(other.DestinationIDs) for i, dc := range dcs.Chargers { if !dc.Equal(other.Chargers[i]) { return false diff --git a/utils/derivedchargers_test.go b/utils/derivedchargers_test.go index 4a2fffe31..7de46b728 100644 --- a/utils/derivedchargers_test.go +++ b/utils/derivedchargers_test.go @@ -27,29 +27,29 @@ func TestAppendDerivedChargers(t *testing.T) { var err error dcs := &DerivedChargers{Chargers: make([]*DerivedCharger, 0)} - if _, err := dcs.Append(&DerivedCharger{RunId: DEFAULT_RUNID}); err == nil { - t.Error("Failed to detect using of the default runid") + if _, err := dcs.Append(&DerivedCharger{RunID: DEFAULT_RUNID}); err == nil { + t.Error("Failed to detect using of the default RunID") } - if dcs, err = dcs.Append(&DerivedCharger{RunId: "FIRST_RUNID"}); err != nil { - t.Error("Failed to add runid") + if dcs, err = dcs.Append(&DerivedCharger{RunID: "FIRST_RunID"}); err != nil { + t.Error("Failed to add RunID") } else if len(dcs.Chargers) != 1 { t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs.Chargers)) } - if dcs, err = dcs.Append(&DerivedCharger{RunId: "SECOND_RUNID"}); err != nil { - t.Error("Failed to add runid") + if dcs, err = dcs.Append(&DerivedCharger{RunID: "SECOND_RunID"}); err != nil { + t.Error("Failed to add RunID") } else if len(dcs.Chargers) != 2 { t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs.Chargers)) } - if _, err := dcs.Append(&DerivedCharger{RunId: "SECOND_RUNID"}); err == nil { - t.Error("Failed to detect duplicate runid") + if _, err := dcs.Append(&DerivedCharger{RunID: "SECOND_RunID"}); err == nil { + t.Error("Failed to detect duplicate RunID") } } func TestNewDerivedCharger(t *testing.T) { edc1 := &DerivedCharger{ - RunId: "test1", + RunID: "test1", RunFilters: "", - ReqTypeField: "reqtype1", + RequestTypeField: "reqtype1", DirectionField: "direction1", TenantField: "tenant1", CategoryField: "tor1", @@ -57,7 +57,7 @@ func TestNewDerivedCharger(t *testing.T) { SubjectField: "subject1", DestinationField: "destination1", SetupTimeField: "setuptime1", - PddField: "pdd1", + PDDField: "pdd1", AnswerTimeField: "answertime1", UsageField: "duration1", SupplierField: "supplier1", @@ -72,9 +72,9 @@ func TestNewDerivedCharger(t *testing.T) { t.Errorf("Expecting: %v, received: %v", edc1, dc1) } edc2 := &DerivedCharger{ - RunId: "test2", + RunID: "test2", RunFilters: "^cdr_source/tdm_cdrs/", - ReqTypeField: "~reqtype2:s/sip:(.+)/$1/", + RequestTypeField: "~reqtype2:s/sip:(.+)/$1/", DirectionField: "~direction2:s/sip:(.+)/$1/", TenantField: "~tenant2:s/sip:(.+)/$1/", CategoryField: "~tor2:s/sip:(.+)/$1/", @@ -82,7 +82,7 @@ func TestNewDerivedCharger(t *testing.T) { SubjectField: "~subject2:s/sip:(.+)/$1/", DestinationField: "~destination2:s/sip:(.+)/$1/", SetupTimeField: "~setuptime2:s/sip:(.+)/$1/", - PddField: "~pdd:s/sip:(.+)/$1/", + PDDField: "~pdd:s/sip:(.+)/$1/", AnswerTimeField: "~answertime2:s/sip:(.+)/$1/", UsageField: "~duration2:s/sip:(.+)/$1/", SupplierField: "~supplier2:s/(.+)/$1/", @@ -91,7 +91,7 @@ func TestNewDerivedCharger(t *testing.T) { RatedField: "~cgr_rated:s/(.+)/$1/", } edc2.rsrRunFilters, _ = ParseRSRFields("^cdr_source/tdm_cdrs/", INFIELD_SEP) - edc2.rsrReqTypeField, _ = NewRSRField("~reqtype2:s/sip:(.+)/$1/") + edc2.rsrRequestTypeField, _ = NewRSRField("~reqtype2:s/sip:(.+)/$1/") edc2.rsrDirectionField, _ = NewRSRField("~direction2:s/sip:(.+)/$1/") edc2.rsrTenantField, _ = NewRSRField("~tenant2:s/sip:(.+)/$1/") edc2.rsrCategoryField, _ = NewRSRField("~tor2:s/sip:(.+)/$1/") @@ -137,20 +137,20 @@ func TestDerivedChargersKey(t *testing.T) { func TestAppendDefaultRun(t *testing.T) { dc1 := &DerivedChargers{} - dcDf := &DerivedCharger{RunId: DEFAULT_RUNID, RunFilters: "", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, + dcDf := &DerivedCharger{RunID: DEFAULT_RUNID, RunFilters: "", RequestTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: META_DEFAULT, SubjectField: META_DEFAULT, - DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, SupplierField: META_DEFAULT, + DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PDDField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, SupplierField: META_DEFAULT, DisconnectCauseField: META_DEFAULT, CostField: META_DEFAULT, RatedField: META_DEFAULT} eDc1 := &DerivedChargers{Chargers: []*DerivedCharger{dcDf}} if dc1, _ = dc1.AppendDefaultRun(); !reflect.DeepEqual(dc1, eDc1) { t.Errorf("Expecting: %+v, received: %+v", eDc1.Chargers[0], dc1.Chargers[0]) } dc2 := &DerivedChargers{Chargers: []*DerivedCharger{ - &DerivedCharger{RunId: "extra1", RunFilters: "", ReqTypeField: "reqtype2", DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, - AccountField: "rif", SubjectField: "rif", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, + &DerivedCharger{RunID: "extra1", RunFilters: "", RequestTypeField: "reqtype2", DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, + AccountField: "rif", SubjectField: "rif", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PDDField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, DisconnectCauseField: META_DEFAULT}, - &DerivedCharger{RunId: "extra2", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, - AccountField: "ivo", SubjectField: "ivo", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, + &DerivedCharger{RunID: "extra2", RequestTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, + AccountField: "ivo", SubjectField: "ivo", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PDDField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, SupplierField: META_DEFAULT, DisconnectCauseField: META_DEFAULT}}, } eDc2 := &DerivedChargers{}