diff --git a/cdrc/csv.go b/cdrc/csv.go index a598b50fa..d3a0655d7 100644 --- a/cdrc/csv.go +++ b/cdrc/csv.go @@ -157,14 +157,14 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *con cdrFldCfg.Value = config.NewRSRParsersMustCompile("~"+strconv.Itoa(len(record)-1), true) // in case of flatstore, last element will be the duration computed by us } } - var fieldVal string + fldVals := make(map[string]string) switch cdrFldCfg.Type { case utils.META_COMPOSED: out, err := cdrFldCfg.Value.ParseDataProvider(csvProvider, utils.NestingSep) if err != nil { return nil, err } - fieldVal = out + fldVals[cdrFldCfg.FieldId] += out case utils.MetaUnixTimestamp: out, err := cdrFldCfg.Value.ParseDataProvider(csvProvider, utils.NestingSep) if err != nil { @@ -174,13 +174,13 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *con if err != nil { return nil, err } - fieldVal += strconv.Itoa(int(t.Unix())) + fldVals[cdrFldCfg.FieldId] += strconv.Itoa(int(t.Unix())) case utils.META_HTTP_POST: lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of storedCdr to http server default: return nil, fmt.Errorf("Unsupported field type: %s", cdrFldCfg.Type) } - if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fieldVal, self.timezone); err != nil { + if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fldVals[cdrFldCfg.FieldId], self.timezone); err != nil { return nil, err } } diff --git a/cdrc/fwv.go b/cdrc/fwv.go index e266f28c3..c30fa986d 100644 --- a/cdrc/fwv.go +++ b/cdrc/fwv.go @@ -171,25 +171,25 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *confi continue // Not passes filters, ignore this CDR } } - var fieldVal string + fldVals := make(map[string]string) switch cdrFldCfg.Type { case utils.META_COMPOSED: out, err := cdrFldCfg.Value.ParseDataProvider(fwvProvider, utils.NestingSep) if err != nil { return nil, err } - fieldVal = out + fldVals[cdrFldCfg.FieldId] += out case utils.META_HTTP_POST: lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of storedCdr to http server default: //return nil, fmt.Errorf("Unsupported field type: %s", cdrFldCfg.Type) continue // Don't do anything for unsupported fields } - if fieldVal, err = utils.FmtFieldWidth(cdrFldCfg.Tag, fieldVal, cdrFldCfg.Width, + if fldVals[cdrFldCfg.FieldId], err = utils.FmtFieldWidth(cdrFldCfg.Tag, fldVals[cdrFldCfg.FieldId], cdrFldCfg.Width, cdrFldCfg.Strip, cdrFldCfg.Padding, cdrFldCfg.Mandatory); err != nil { return nil, err } - if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fieldVal, self.timezone); err != nil { + if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fldVals[cdrFldCfg.FieldId], self.timezone); err != nil { return nil, err } } diff --git a/cdrc/xml_it_test.go b/cdrc/xml_it_test.go index a53392360..2562a9d6d 100644 --- a/cdrc/xml_it_test.go +++ b/cdrc/xml_it_test.go @@ -302,3 +302,89 @@ func TestXmlIT3KillEngine(t *testing.T) { t.Error(err) } } + +// Begin tests for cdrc xml with new filters +func TestXmlIT4InitConfig(t *testing.T) { + var err error + xmlCfgPath = path.Join(*dataDir, "conf", "samples", "cdrcxmlwithfilter") + if xmlCfg, err = config.NewCGRConfigFromFolder(xmlCfgPath); err != nil { + t.Fatal("Got config error: ", err.Error()) + } +} + +// InitDb so we can rely on count +func TestXmlIT4InitCdrDb(t *testing.T) { + if err := engine.InitStorDb(xmlCfg); err != nil { + t.Fatal(err) + } +} + +func TestXmlIT4CreateCdrDirs(t *testing.T) { + for _, cdrcProfiles := range xmlCfg.CdrcProfiles { + for _, cdrcInst := range cdrcProfiles { + for _, dir := range []string{cdrcInst.CdrInDir, cdrcInst.CdrOutDir} { + if err := os.RemoveAll(dir); err != nil { + t.Fatal("Error removing folder: ", dir, err) + } + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatal("Error creating folder: ", dir, err) + } + } + if cdrcInst.ID == "msw_xml2" { // Initialize the folders to check later + xmlPathIn1 = cdrcInst.CdrInDir + xmlPathOut1 = cdrcInst.CdrOutDir + } + } + } +} + +func TestXmlIT4StartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(xmlCfgPath, *waitRater); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func TestXmlIT4RpcConn(t *testing.T) { + var err error + cdrcXmlRPC, err = jsonrpc.Dial("tcp", xmlCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } +} + +// The default scenario, out of cdrc defined in .cfg file +func TestXmlIT4HandleCdr1File(t *testing.T) { + fileName := "file1.xml" + tmpFilePath := path.Join("/tmp", fileName) + if err := ioutil.WriteFile(tmpFilePath, []byte(xmlContent), 0644); err != nil { + t.Fatal(err.Error()) + } + if err := os.Rename(tmpFilePath, path.Join(xmlPathIn1, fileName)); err != nil { + t.Fatal("Error moving file to processing directory: ", err) + } +} + +func TestXmlIT4ProcessedFiles(t *testing.T) { + time.Sleep(time.Duration(2**waitRater) * time.Millisecond) + if outContent1, err := ioutil.ReadFile(path.Join(xmlPathOut1, "file1.xml")); err != nil { + t.Error(err) + } else if xmlContent != string(outContent1) { + t.Errorf("Expecting: %q, received: %q", xmlContent, string(outContent1)) + } +} + +func TestXmlIT4AnalyseCDRs(t *testing.T) { + var reply []*engine.ExternalCDR + if err := cdrcXmlRPC.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{}, &reply); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(reply) != 2 { + t.Error("Unexpected number of CDRs returned: ", len(reply)) + } +} + +func TestXmlIT4KillEngine(t *testing.T) { + if err := engine.KillEngine(*waitRater); err != nil { + t.Error(err) + } +} diff --git a/data/conf/samples/cdrcxmlwithfilter/cgrates.json b/data/conf/samples/cdrcxmlwithfilter/cgrates.json index 580107b22..eeca926ae 100755 --- a/data/conf/samples/cdrcxmlwithfilter/cgrates.json +++ b/data/conf/samples/cdrcxmlwithfilter/cgrates.json @@ -64,6 +64,31 @@ {"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*substract_usage", "value": "~File.CDRs.Call.ReleaseTime;|;~File.CDRs.Call.ConnectTime", "mandatory": true} ], }, + { + "id": "msw_xml2", // identifier of the CDRC runner + "enabled": true, // enable CDR client functionality + "cdr_format": "xml", // CDR file format