diff --git a/engine/cdr.go b/engine/cdr.go index 86003e8d0..cde9fc063 100644 --- a/engine/cdr.go +++ b/engine/cdr.go @@ -20,10 +20,8 @@ package engine import ( "encoding/json" - "fmt" "math" "strconv" - "strings" "time" "github.com/cgrates/cgrates/config" @@ -279,143 +277,6 @@ func (cdr *CDR) String() string { return string(mrsh) } -// combimedCdrFieldVal groups together CDRs with same CGRID and combines their values matching filter field ID -func (cdr *CDR) combimedCdrFieldVal(cfgCdrFld *config.FCTemplate, groupCDRs []*CDR, filterS *FilterS) (string, error) { - var combimedVal string // Will result as combination of the field values, filters must match - - for _, grpCDR := range groupCDRs { - if cdr.CGRID != grpCDR.CGRID { - continue // We only care about cdrs with same primary cdr behind - } - if pass, err := filterS.Pass(grpCDR.Tenant, cfgCdrFld.Filters, grpCDR.AsMapStorage()); err != nil { - return utils.EmptyString, err - } else if !pass { - continue - } - combimedVal += grpCDR.FieldsAsString(cfgCdrFld.Value) - - } - return combimedVal, nil -} - -// Extracts the value specified by cfgHdr out of cdr, used for export values -func (cdr *CDR) exportFieldValue(cfgCdrFld *config.FCTemplate, filterS *FilterS) (retVal string, err error) { - for _, rsrFld := range cfgCdrFld.Value { - var cdrVal string - var roundDec int - switch cfgCdrFld.Path { - case utils.MetaExp + utils.NestingSep + utils.Cost: - roundDec = config.CgrConfig().GeneralCfg().RoundingDecimals - if cfgCdrFld.RoundingDecimals != nil { - roundDec = *cfgCdrFld.RoundingDecimals - } - cdrVal = cdr.FormatCost(cfgCdrFld.CostShiftDigits, roundDec) - case utils.MetaExp + utils.NestingSep + utils.SetupTime: - cdrVal = cdr.SetupTime.Format(cfgCdrFld.Layout) - case utils.MetaExp + utils.NestingSep + utils.AnswerTime: // Format time based on layout - cdrVal = cdr.AnswerTime.Format(cfgCdrFld.Layout) - case utils.MetaExp + utils.NestingSep + utils.Destination: - cdrVal, err = cdr.FieldAsString(rsrFld) - if err != nil { - return "", err - } - if cfgCdrFld.MaskLen != -1 && len(cfgCdrFld.MaskDestID) != 0 && - CachedDestHasPrefix(cfgCdrFld.MaskDestID, cdrVal) { - cdrVal = utils.MaskSuffix(cdrVal, cfgCdrFld.MaskLen) - } - default: - cdrVal, err = cdr.FieldAsString(rsrFld) - if err != nil { - return "", err - } - } - retVal += cdrVal - } - return -} - -func (cdr *CDR) formatField(cfgFld *config.FCTemplate, groupedCDRs []*CDR, - filterS *FilterS) (outVal string, err error) { - switch cfgFld.Type { - case utils.MetaFiller: - outVal, err = cfgFld.Value.ParseValue(utils.EmptyString) - cfgFld.Padding = utils.MetaRight - case utils.MetaConstant: - outVal, err = cfgFld.Value.ParseValue(utils.EmptyString) - case utils.MetaDateTime: // Convert the requested field value into datetime with layout - rawVal, err := cdr.exportFieldValue(cfgFld, filterS) - if err != nil { - return "", err - } - dtFld, err := utils.ParseTimeDetectLayout(rawVal, cfgFld.Timezone) - if err != nil { // Only one rule makes sense here - return "", err - } - outVal = dtFld.Format(cfgFld.Layout) - case utils.MetaHTTPPost: - var outValByte []byte - var httpAddr string - httpAddr, err = cfgFld.Value.ParseValue(utils.EmptyString) - if err != nil { - return "", err - } - var jsn []byte - jsn, err = json.Marshal(cdr) - if err != nil { - return "", err - } - if len(httpAddr) == 0 { - err = fmt.Errorf("Empty http address for field %s type %s", cfgFld.Tag, cfgFld.Type) - } else if outValByte, err = HTTPPostJSON(httpAddr, jsn); err == nil { - outVal = string(outValByte) - if len(outVal) == 0 && cfgFld.Mandatory { - err = fmt.Errorf("Empty result for http_post field: %s", cfgFld.Tag) - } - } - case utils.MetaCombimed: - outVal, err = cdr.combimedCdrFieldVal(cfgFld, groupedCDRs, filterS) - case utils.MetaComposed, utils.MetaVariable: - outVal, err = cdr.exportFieldValue(cfgFld, filterS) - case utils.MetaMaskedDestination: - if len(cfgFld.MaskDestID) != 0 && CachedDestHasPrefix(cfgFld.MaskDestID, cdr.Destination) { - outVal = "1" - } else { - outVal = "0" - } - } - if err != nil && - (err != utils.ErrNotFound || cfgFld.Mandatory) { - return "", err - } - return utils.FmtFieldWidth(cfgFld.Tag, outVal, cfgFld.Width, cfgFld.Strip, cfgFld.Padding, cfgFld.Mandatory) -} - -// AsExportRecord is used in place where we need to export the CDR based on an export template -// ExportRecord is a []string to keep it compatible with encoding/csv Writer -func (cdr *CDR) AsExportRecord(exportFields []*config.FCTemplate, groupedCDRs []*CDR, - filterS *FilterS) (expRecord []string, err error) { - nM := cdr.AsMapStorage() - for _, cfgFld := range exportFields { - if !strings.HasPrefix(cfgFld.Path, utils.MetaExp+utils.NestingSep) { - continue - } - if pass, err := filterS.Pass(cdr.Tenant, - cfgFld.Filters, nM); err != nil { - return []string{}, err - } else if !pass { - continue - } - var fmtOut string - if fmtOut, err = cdr.formatField(cfgFld, groupedCDRs, filterS); err != nil { - utils.Logger.Warning(fmt.Sprintf(" error: %s exporting field: %s, CDR: %s\n", - err.Error(), utils.ToJSON(cfgFld), utils.ToJSON(cdr))) - return nil, err - } - expRecord = append(expRecord, fmtOut) - } - return expRecord, nil -} - // AsCDRsql converts the CDR into the format used for SQL storage func (cdr *CDR) AsCDRsql() (cdrSQL *CDRsql) { cdrSQL = new(CDRsql) diff --git a/engine/cdr_test.go b/engine/cdr_test.go index aef197f97..4e0e6d750 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -653,239 +653,6 @@ func TestCDRTestCDRAsMapStringIface2(t *testing.T) { } } -func TestCDRAsExportRecord(t *testing.T) { - cc := &CallCost{ - Category: "generic", - Tenant: "cgrates.org", - Subject: "1001", - Account: "1001", - Destination: "data", - ToR: "*data", - Cost: 0, - AccountSummary: &AccountSummary{ - Tenant: "cgrates.org", - ID: "AccountFromAccountSummary", - }, - } - eventCost := NewEventCostFromCallCost(cc, "TestCDRTestCDRAsMapStringIface2", utils.MetaDefault) - eventCost.RatingFilters = RatingFilters{ - "3d99c91": RatingMatchedFilters{ - "DestinationID": "CustomDestination", - "DestinationPrefix": "26377", - "RatingPlanID": "RP_ZW_v1", - }, - } - - cdr := &CDR{ - CGRID: utils.Sha1("dsafdsaf", - time.Unix(1383813745, 0).UTC().String()), - ToR: utils.MetaVoice, OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Unix(1383813745, 0).UTC(), - AnswerTime: time.Unix(1383813746, 0).UTC(), - Usage: 10 * time.Second, - RunID: utils.MetaDefault, Cost: 1.01, - ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}, - CostDetails: eventCost, - } - - prsr := config.NewRSRParsersMustCompile(utils.DynamicDataPrefix+utils.MetaReq+utils.NestingSep+utils.Destination, utils.InfieldSep) - cfgCdrFld := &config.FCTemplate{ - Tag: "destination", - Path: "*exp.Destination", - Type: utils.MetaComposed, - Value: prsr, - Timezone: "UTC", - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != cdr.Destination { - t.Errorf("Expecting:\n%s\nReceived:\n%s", cdr.Destination, expRecord) - } - if err := dm.SetReverseDestination("MASKED_DESTINATIONS", []string{"+4986517174963"}, - utils.NonTransactional); err != nil { - t.Error(err) - } - - cfgCdrFld = &config.FCTemplate{ - Tag: "Destination", - Path: "*exp.Destination", - Type: utils.MetaComposed, - Value: prsr, - MaskDestID: "MASKED_DESTINATIONS", - MaskLen: 3, - } - eDst := "+4986517174***" - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != eDst { - t.Errorf("Expecting:\n%s\nReceived:\n%s", eDst, expRecord[0]) - } - - cfgCdrFld = &config.FCTemplate{ - Tag: "MaskedDest", - Path: "*exp.MaskedDest", - Type: utils.MetaMaskedDestination, - Value: prsr, - MaskDestID: "MASKED_DESTINATIONS", - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != "1" { - t.Errorf("Expecting:\n%s\nReceived:\n%s", "1", expRecord[0]) - } - defaultCfg := config.NewDefaultCGRConfig() - data := NewInternalDB(nil, nil, true) - dmForCDR := NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - cfgCdrFld = &config.FCTemplate{ - Tag: "destination", - Path: "*exp.Destination", - Type: utils.MetaComposed, - Value: prsr, - Filters: []string{"*string:~*req.Tenant:itsyscom.com"}, - Timezone: "UTC", - } - if rcrd, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, &FilterS{dm: dmForCDR, cfg: defaultCfg}); err != nil { - t.Error(err) - } else if len(rcrd) != 0 { - t.Error("failed using filter") - } - - // Test MetaDateTime - prsr = config.NewRSRParsersMustCompile("~*req.stop_time", utils.InfieldSep) - layout := "2006-01-02 15:04:05" - cfgCdrFld = &config.FCTemplate{ - Tag: "stop_time", - Type: utils.MetaDateTime, - Path: "*exp.stop_time", - Value: prsr, - Layout: layout, - Timezone: "UTC", - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, &FilterS{dm: dmForCDR, cfg: defaultCfg}); err != nil { - t.Error(err) - } else if expRecord[0] != "2014-06-11 19:19:00" { - t.Error("Expecting: 2014-06-11 19:19:00, got: ", expRecord[0]) - } - - // Test filter - cfgCdrFld = &config.FCTemplate{ - Tag: "stop_time", - Type: utils.MetaDateTime, - Path: "*exp.stop_time", - Value: prsr, - Filters: []string{"*string:~*req.Tenant:itsyscom.com"}, - Layout: layout, - Timezone: "UTC", - } - if rcrd, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, &FilterS{dm: dmForCDR, cfg: defaultCfg}); err != nil { - t.Error(err) - } else if len(rcrd) != 0 { - t.Error("failed using filter") - } - - prsr = config.NewRSRParsersMustCompile("~*req.fieldextr2", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "stop_time", - Type: utils.MetaDateTime, - Path: "*exp.stop_time", - Value: prsr, - Layout: layout, - Timezone: "UTC"} - // Test time parse error - if _, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err == nil { - t.Error("Should give error here, got none.") - } - - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.CGRID", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "CGRIDFromCostDetails", - Type: utils.MetaComposed, - Path: "*exp.CGRIDFromCostDetails", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != cdr.CostDetails.CGRID { - t.Errorf("Expecting:\n%s\nReceived:\n%s", cdr.CostDetails.CGRID, expRecord) - } - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.AccountSummary.ID", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "AccountID", - Type: utils.MetaComposed, - Path: "*exp.CustomAccountID", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != cdr.CostDetails.AccountSummary.ID { - t.Errorf("Expecting:\n%s\nReceived:\n%s", cdr.CostDetails.AccountSummary.ID, expRecord) - } - - expected := `{"3d99c91":{"DestinationID":"CustomDestination","DestinationPrefix":"26377","RatingPlanID":"RP_ZW_v1"}}` - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.RatingFilters", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "DestinationID", - Type: utils.MetaComposed, - Path: "*exp.CustomDestinationID", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != expected { - t.Errorf("Expecting: <%q>,\n Received: <%q>", expected, expRecord[0]) - } - - expected = "RP_ZW_v1" - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.RatingFilters:s/RatingPlanID\"\\s?\\:\\s?\"([^\"]*)\".*/$1/", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "DestinationID", - Type: utils.MetaComposed, - Path: "*exp.CustomDestinationID", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != expected { - t.Errorf("Expecting: <%q>,\n Received: <%q>", expected, expRecord[0]) - } - - expected = "CustomDestination" - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.RatingFilters:s/DestinationID\"\\s?\\:\\s?\"([^\"]*)\".*/$1/", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "DestinationID", - Type: utils.MetaComposed, - Path: "*exp.CustomDestinationID", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != expected { - t.Errorf("Expecting: <%q>,\n Received: <%q>", expected, expRecord[0]) - } - - expected = "26377" - prsr = config.NewRSRParsersMustCompile("~*req.CostDetails.RatingFilters:s/DestinationPrefix\"\\s?\\:\\s?\"([^\"]*)\".*/$1/", utils.InfieldSep) - cfgCdrFld = &config.FCTemplate{ - Tag: "DestinationID", - Type: utils.MetaComposed, - Path: "*exp.CustomDestinationID", - Value: prsr, - } - if expRecord, err := cdr.AsExportRecord([]*config.FCTemplate{cfgCdrFld}, nil, nil); err != nil { - t.Error(err) - } else if expRecord[0] != expected { - t.Errorf("Expecting: <%q>,\n Received: <%q>", expected, expRecord[0]) - } - -} - func TestCDRAsCDRsql(t *testing.T) { cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, @@ -1074,242 +841,3 @@ func TestCDRAddDefaults(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eCDR, cdr) } } - -func TestCDRexportFieldValue(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.MetaVoice, - OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - Source: utils.UnitTest, - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.MetaDefault, - Usage: 10 * time.Second, - Cost: 1.01, - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - } - - cfgCdrFld := &config.FCTemplate{Path: "*exp.SetupTime", Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~SetupTime", utils.InfieldSep), Layout: time.RFC3339} - - eVal := "2013-11-07T08:42:20Z" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, utils.ToJSON(val)) - } - -} - -func TestCDReRoundingDecimals(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.MetaVoice, - OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - Source: utils.UnitTest, - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.MetaDefault, - Usage: 10 * time.Second, - Cost: 1.32165, - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - } - - cfgCdrFld := &config.FCTemplate{ - Path: "*exp.Cost", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~SetupTime", utils.InfieldSep), - } - - //5 is the default value for rounding decimals - eVal := "1.32165" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 4 - eVal = "1.3216" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 2 - eVal = "1.32" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 3 - eVal = "1.322" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 1 - eVal = "1.3" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 2 - eVal = "1.32" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 4 - eVal = "1.3216" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 1 - eVal = "1.3" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 4 - eVal = "1.3216" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - eVal = "1.3216" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - config.CgrConfig().GeneralCfg().RoundingDecimals = 3 - eVal = "1.322" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - config.CgrConfig().GeneralCfg().RoundingDecimals = 4 - eVal = "1.3216" - if val, err := cdr.exportFieldValue(cfgCdrFld, nil); err != nil { - t.Error(err) - } else if val != eVal { - t.Errorf("Expecting: %+v, received: %+v", eVal, val) - } - - //resetore roundingdecimals value - config.CgrConfig().GeneralCfg().RoundingDecimals = 5 -} - -func TestCDRcombimedCdrFieldVal(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.MetaVoice, - OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - Source: utils.UnitTest, - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.MetaDefault, - Usage: 10 * time.Second, - Cost: 1.32165, - ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, - } - groupCDRs := []*CDR{ - cdr, - { - CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), - OrderID: 124, - ToR: utils.MetaVoice, - OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - Source: utils.UnitTest, - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: "testRun1", - Usage: 10 * time.Second, - Cost: 1.22, - }, - { - CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), - OrderID: 125, - ToR: utils.MetaVoice, - OriginID: "dsafdsaf", - OriginHost: "192.168.1.1", - Source: utils.UnitTest, - RequestType: utils.MetaRated, - Tenant: "cgrates.org", - Category: "call", - Account: "1001", - Subject: "1001", - Destination: "+4986517174963", - SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), - AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: "testRun2", - Usage: 10 * time.Second, - Cost: 1.764, - }, - } - - tpFld := &config.FCTemplate{ - Tag: "TestCombiMed", - Type: utils.MetaCombimed, - Filters: []string{"*string:~*req.RunID:testRun1"}, - Value: config.NewRSRParsersMustCompile("~*req.Cost", utils.InfieldSep), - } - cfg := config.NewDefaultCGRConfig() - - if out, err := cdr.combimedCdrFieldVal(tpFld, groupCDRs, &FilterS{cfg: cfg}); err != nil { - t.Error(err) - } else if out != "1.22" { - t.Errorf("Expected : %+v, received: %+v", "1.22", out) - } - -}