mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-21 07:08:45 +05:00
Cdrc now supports multiple field sources
This commit is contained in:
22
cdrc/cdrc.go
22
cdrc/cdrc.go
@@ -43,7 +43,7 @@ const (
|
||||
FS_CSV = "freeswitch_csv"
|
||||
)
|
||||
|
||||
func NewCdrc(cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, csvSep string, cdrFields map[string]*utils.RSRField, cdrServer *cdrs.CDRS) (*Cdrc, error) {
|
||||
func NewCdrc(cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, csvSep string, cdrFields map[string][]*utils.RSRField, cdrServer *cdrs.CDRS) (*Cdrc, error) {
|
||||
if len(csvSep) != 1 {
|
||||
return nil, fmt.Errorf("Unsupported csv separator: %s", csvSep)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ type Cdrc struct {
|
||||
cdrSourceId string
|
||||
runDelay time.Duration
|
||||
csvSep rune
|
||||
cdrFields map[string]*utils.RSRField
|
||||
cdrFields map[string][]*utils.RSRField
|
||||
cdrServer *cdrs.CDRS // Reference towards internal cdrServer if that is the case
|
||||
httpClient *http.Client
|
||||
}
|
||||
@@ -89,16 +89,18 @@ func (self *Cdrc) Run() error {
|
||||
func (self *Cdrc) recordToStoredCdr(record []string) (*utils.StoredCdr, error) {
|
||||
storedCdr := &utils.StoredCdr{CdrHost: "0.0.0.0", CdrSource: self.cdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
|
||||
var err error
|
||||
for cfgFieldName, cfgFieldRSR := range self.cdrFields {
|
||||
for cfgFieldName, cfgFieldRSRs := range self.cdrFields {
|
||||
var fieldVal string
|
||||
if utils.IsSliceMember([]string{CSV, FS_CSV}, self.cdrType) {
|
||||
if strings.HasPrefix(cfgFieldRSR.Id, utils.STATIC_VALUE_PREFIX) {
|
||||
fieldVal = cfgFieldRSR.ParseValue("PLACEHOLDER")
|
||||
} else { // Dynamic value extracted using index
|
||||
if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cfgFieldName)
|
||||
} else {
|
||||
fieldVal = cfgFieldRSR.ParseValue(record[cfgFieldIdx])
|
||||
for _, cfgFieldRSR := range cfgFieldRSRs {
|
||||
if strings.HasPrefix(cfgFieldRSR.Id, utils.STATIC_VALUE_PREFIX) {
|
||||
fieldVal += cfgFieldRSR.ParseValue("PLACEHOLDER")
|
||||
} else { // Dynamic value extracted using index
|
||||
if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx {
|
||||
return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cfgFieldName)
|
||||
} else {
|
||||
fieldVal += cfgFieldRSR.ParseValue(record[cfgFieldIdx])
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Modify here when we add more supported cdr formats
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
|
||||
func TestRecordForkCdr(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cgrConfig.CdrcCdrFields["supplier"] = &utils.RSRField{Id: "14"}
|
||||
cgrConfig.CdrcCdrFields["supplier"] = []*utils.RSRField{&utils.RSRField{Id: "14"}}
|
||||
csvSepRune, _ := utf8.DecodeRune([]byte(cgrConfig.CdrcCsvSep))
|
||||
cdrc := &Cdrc{cgrConfig.CdrcCdrs, cgrConfig.CdrcCdrType, cgrConfig.CdrcCdrInDir, cgrConfig.CdrcCdrOutDir, cgrConfig.CdrcSourceId, cgrConfig.CdrcRunDelay, csvSepRune,
|
||||
cgrConfig.CdrcCdrFields, new(cdrs.CDRS), nil}
|
||||
|
||||
@@ -124,7 +124,7 @@ func startMediator(responder *engine.Responder, loggerDb engine.LogStorage, cdrD
|
||||
}
|
||||
|
||||
// Fires up a cdrc instance
|
||||
func startCdrc(cdrsChan chan struct{}, cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, csvSep string, cdrFields map[string]*utils.RSRField) {
|
||||
func startCdrc(cdrsChan chan struct{}, cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, csvSep string, cdrFields map[string][]*utils.RSRField) {
|
||||
if cdrsAddress == utils.INTERNAL {
|
||||
<-cdrsChan // Wait for CDRServer to come up before start processing
|
||||
}
|
||||
|
||||
@@ -88,20 +88,20 @@ type CGRConfig struct {
|
||||
RaterBalancer string // balancer address host:port
|
||||
BalancerEnabled bool
|
||||
SchedulerEnabled bool
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
|
||||
CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
CdrStatsConfigs []*CdrStatsConfig // Active cdr stats configuration instances
|
||||
CdreDefaultInstance *CdreConfig // Will be used in the case no specific one selected by API
|
||||
CdrcEnabled bool // Enable CDR client functionality
|
||||
CdrcCdrs string // Address where to reach CDR server
|
||||
CdrcRunDelay time.Duration // Sleep interval between consecutive runs, 0 to use automation via inotify
|
||||
CdrcCdrType string // CDR file format <csv>.
|
||||
CdrcCsvSep string // Separator used in case of csv files. One character only supported.
|
||||
CdrcCdrInDir string // Absolute path towards the directory where the CDRs are stored.
|
||||
CdrcCdrOutDir string // Absolute path towards the directory where processed CDRs will be moved.
|
||||
CdrcSourceId string // Tag identifying the source of the CDRs within CGRS database.
|
||||
CdrcCdrFields map[string]*utils.RSRField // FieldName/RSRField format. Index number in case of .csv cdrs.
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
|
||||
CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
CdrStatsConfigs []*CdrStatsConfig // Active cdr stats configuration instances
|
||||
CdreDefaultInstance *CdreConfig // Will be used in the case no specific one selected by API
|
||||
CdrcEnabled bool // Enable CDR client functionality
|
||||
CdrcCdrs string // Address where to reach CDR server
|
||||
CdrcRunDelay time.Duration // Sleep interval between consecutive runs, 0 to use automation via inotify
|
||||
CdrcCdrType string // CDR file format <csv>.
|
||||
CdrcCsvSep string // Separator used in case of csv files. One character only supported.
|
||||
CdrcCdrInDir string // Absolute path towards the directory where the CDRs are stored.
|
||||
CdrcCdrOutDir string // Absolute path towards the directory where processed CDRs will be moved.
|
||||
CdrcSourceId string // Tag identifying the source of the CDRs within CGRS database.
|
||||
CdrcCdrFields map[string][]*utils.RSRField // FieldName/RSRField format. Index number in case of .csv cdrs.
|
||||
SMEnabled bool
|
||||
SMSwitchType string
|
||||
SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
|
||||
@@ -174,19 +174,19 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.CdrcCdrInDir = "/var/log/cgrates/cdrc/in"
|
||||
self.CdrcCdrOutDir = "/var/log/cgrates/cdrc/out"
|
||||
self.CdrcSourceId = "csv"
|
||||
self.CdrcCdrFields = map[string]*utils.RSRField{
|
||||
utils.TOR: &utils.RSRField{Id: "2"},
|
||||
utils.ACCID: &utils.RSRField{Id: "3"},
|
||||
utils.REQTYPE: &utils.RSRField{Id: "4"},
|
||||
utils.DIRECTION: &utils.RSRField{Id: "5"},
|
||||
utils.TENANT: &utils.RSRField{Id: "6"},
|
||||
utils.CATEGORY: &utils.RSRField{Id: "7"},
|
||||
utils.ACCOUNT: &utils.RSRField{Id: "8"},
|
||||
utils.SUBJECT: &utils.RSRField{Id: "9"},
|
||||
utils.DESTINATION: &utils.RSRField{Id: "10"},
|
||||
utils.SETUP_TIME: &utils.RSRField{Id: "11"},
|
||||
utils.ANSWER_TIME: &utils.RSRField{Id: "12"},
|
||||
utils.USAGE: &utils.RSRField{Id: "13"},
|
||||
self.CdrcCdrFields = map[string][]*utils.RSRField{
|
||||
utils.TOR: []*utils.RSRField{&utils.RSRField{Id: "2"}},
|
||||
utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "3"}},
|
||||
utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "4"}},
|
||||
utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "5"}},
|
||||
utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "6"}},
|
||||
utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "7"}},
|
||||
utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "8"}},
|
||||
utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "9"}},
|
||||
utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "10"}},
|
||||
utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "11"}},
|
||||
utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "12"}},
|
||||
utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "13"}},
|
||||
}
|
||||
self.MediatorEnabled = false
|
||||
self.MediatorRater = "internal"
|
||||
@@ -221,9 +221,11 @@ func (self *CGRConfig) checkConfigSanity() error {
|
||||
return errors.New("CdrC enabled but no fields to be processed defined!")
|
||||
}
|
||||
if self.CdrcCdrType == utils.CSV {
|
||||
for _, rsrFld := range self.CdrcCdrFields {
|
||||
if _, errConv := strconv.Atoi(rsrFld.Id); errConv != nil {
|
||||
return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.Id)
|
||||
for _, rsrFldLst := range self.CdrcCdrFields {
|
||||
for _, rsrFld := range rsrFldLst {
|
||||
if _, errConv := strconv.Atoi(rsrFld.Id); errConv != nil {
|
||||
return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,19 +91,19 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.CdrcCdrInDir = "/var/log/cgrates/cdrc/in"
|
||||
eCfg.CdrcCdrOutDir = "/var/log/cgrates/cdrc/out"
|
||||
eCfg.CdrcSourceId = "csv"
|
||||
eCfg.CdrcCdrFields = map[string]*utils.RSRField{
|
||||
utils.TOR: &utils.RSRField{Id: "2"},
|
||||
utils.ACCID: &utils.RSRField{Id: "3"},
|
||||
utils.REQTYPE: &utils.RSRField{Id: "4"},
|
||||
utils.DIRECTION: &utils.RSRField{Id: "5"},
|
||||
utils.TENANT: &utils.RSRField{Id: "6"},
|
||||
utils.CATEGORY: &utils.RSRField{Id: "7"},
|
||||
utils.ACCOUNT: &utils.RSRField{Id: "8"},
|
||||
utils.SUBJECT: &utils.RSRField{Id: "9"},
|
||||
utils.DESTINATION: &utils.RSRField{Id: "10"},
|
||||
utils.SETUP_TIME: &utils.RSRField{Id: "11"},
|
||||
utils.ANSWER_TIME: &utils.RSRField{Id: "12"},
|
||||
utils.USAGE: &utils.RSRField{Id: "13"},
|
||||
eCfg.CdrcCdrFields = map[string][]*utils.RSRField{
|
||||
utils.TOR: []*utils.RSRField{&utils.RSRField{Id: "2"}},
|
||||
utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "3"}},
|
||||
utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "4"}},
|
||||
utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "5"}},
|
||||
utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "6"}},
|
||||
utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "7"}},
|
||||
utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "8"}},
|
||||
utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "9"}},
|
||||
utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "10"}},
|
||||
utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "11"}},
|
||||
utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "12"}},
|
||||
utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "13"}},
|
||||
}
|
||||
eCfg.MediatorEnabled = false
|
||||
eCfg.MediatorRater = "internal"
|
||||
@@ -151,11 +151,11 @@ func TestSanityCheck(t *testing.T) {
|
||||
t.Error("Failed to detect missing CDR fields definition")
|
||||
}
|
||||
cfg.CdrcCdrType = utils.CSV
|
||||
cfg.CdrcCdrFields = map[string]*utils.RSRField{utils.ACCID: &utils.RSRField{Id: "test"}}
|
||||
cfg.CdrcCdrFields = map[string][]*utils.RSRField{utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "test"}}}
|
||||
if err := cfg.checkConfigSanity(); err == nil {
|
||||
t.Error("Failed to detect improper use of CDR field names")
|
||||
}
|
||||
cfg.CdrcCdrFields = map[string]*utils.RSRField{"extra1": &utils.RSRField{Id: "test"}}
|
||||
cfg.CdrcCdrFields = map[string][]*utils.RSRField{"extra1": []*utils.RSRField{&utils.RSRField{Id: "test"}}}
|
||||
if err := cfg.checkConfigSanity(); err == nil {
|
||||
t.Error("Failed to detect improper use of CDR field names")
|
||||
}
|
||||
@@ -225,20 +225,20 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.CdrcCdrInDir = "test"
|
||||
eCfg.CdrcCdrOutDir = "test"
|
||||
eCfg.CdrcSourceId = "test"
|
||||
eCfg.CdrcCdrFields = map[string]*utils.RSRField{
|
||||
utils.TOR: &utils.RSRField{Id: "test"},
|
||||
utils.ACCID: &utils.RSRField{Id: "test"},
|
||||
utils.REQTYPE: &utils.RSRField{Id: "test"},
|
||||
utils.DIRECTION: &utils.RSRField{Id: "test"},
|
||||
utils.TENANT: &utils.RSRField{Id: "test"},
|
||||
utils.CATEGORY: &utils.RSRField{Id: "test"},
|
||||
utils.ACCOUNT: &utils.RSRField{Id: "test"},
|
||||
utils.SUBJECT: &utils.RSRField{Id: "test"},
|
||||
utils.DESTINATION: &utils.RSRField{Id: "test"},
|
||||
utils.SETUP_TIME: &utils.RSRField{Id: "test"},
|
||||
utils.ANSWER_TIME: &utils.RSRField{Id: "test"},
|
||||
utils.USAGE: &utils.RSRField{Id: "test"},
|
||||
"test": &utils.RSRField{Id: "test"},
|
||||
eCfg.CdrcCdrFields = map[string][]*utils.RSRField{
|
||||
utils.TOR: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
"test": []*utils.RSRField{&utils.RSRField{Id: "test"}},
|
||||
}
|
||||
eCfg.MediatorEnabled = true
|
||||
eCfg.MediatorRater = "test"
|
||||
|
||||
@@ -120,8 +120,8 @@ func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err
|
||||
}
|
||||
|
||||
func ParseCdrcCdrFields(torFld, accIdFld, reqtypeFld, directionFld, tenantFld, categoryFld, acntFld, subjectFld, destFld,
|
||||
setupTimeFld, answerTimeFld, durFld, extraFlds string) (map[string]*utils.RSRField, error) {
|
||||
cdrcCdrFlds := make(map[string]*utils.RSRField)
|
||||
setupTimeFld, answerTimeFld, durFld, extraFlds string) (map[string][]*utils.RSRField, error) {
|
||||
cdrcCdrFlds := make(map[string][]*utils.RSRField)
|
||||
if len(extraFlds) != 0 {
|
||||
if sepExtraFlds, err := ConfigSlice(extraFlds); err != nil {
|
||||
return nil, err
|
||||
@@ -131,10 +131,10 @@ func ParseCdrcCdrFields(torFld, accIdFld, reqtypeFld, directionFld, tenantFld, c
|
||||
if spltLbl := strings.Split(fldStr, utils.CONCATENATED_KEY_SEP); len(spltLbl) != 2 {
|
||||
return nil, fmt.Errorf("Wrong format for cdrc.extra_fields: %s", fldStr)
|
||||
} else {
|
||||
if rsrFld, err := utils.NewRSRField(spltLbl[1]); err != nil {
|
||||
if rsrFlds, err := utils.ParseRSRFields(spltLbl[1], utils.INFIELD_SEP); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
cdrcCdrFlds[spltLbl[0]] = rsrFld
|
||||
cdrcCdrFlds[spltLbl[0]] = rsrFlds
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,10 +144,10 @@ func ParseCdrcCdrFields(torFld, accIdFld, reqtypeFld, directionFld, tenantFld, c
|
||||
utils.CATEGORY: categoryFld, utils.ACCOUNT: acntFld, utils.SUBJECT: subjectFld, utils.DESTINATION: destFld, utils.SETUP_TIME: setupTimeFld,
|
||||
utils.ANSWER_TIME: answerTimeFld, utils.USAGE: durFld} {
|
||||
if len(fldVal) != 0 {
|
||||
if rsrFld, err := utils.NewRSRField(fldVal); err != nil {
|
||||
if rsrFlds, err := utils.ParseRSRFields(fldVal, utils.INFIELD_SEP); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
cdrcCdrFlds[fldTag] = rsrFld
|
||||
cdrcCdrFlds[fldTag] = rsrFlds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,21 +116,21 @@ answer_time_field = answertime1
|
||||
usage_field = duration1
|
||||
extra_fields = extra1:extraval1,extra2:extraval1
|
||||
`)
|
||||
eCdrcCdrFlds := map[string]*utils.RSRField{
|
||||
utils.TOR: &utils.RSRField{Id: "tor1"},
|
||||
utils.ACCID: &utils.RSRField{Id: "accid1"},
|
||||
utils.REQTYPE: &utils.RSRField{Id: "reqtype1"},
|
||||
utils.DIRECTION: &utils.RSRField{Id: "direction1"},
|
||||
utils.TENANT: &utils.RSRField{Id: "tenant1"},
|
||||
utils.CATEGORY: &utils.RSRField{Id: "category1"},
|
||||
utils.ACCOUNT: &utils.RSRField{Id: "account1"},
|
||||
utils.SUBJECT: &utils.RSRField{Id: "subject1"},
|
||||
utils.DESTINATION: &utils.RSRField{Id: "destination1"},
|
||||
utils.SETUP_TIME: &utils.RSRField{Id: "setuptime1"},
|
||||
utils.ANSWER_TIME: &utils.RSRField{Id: "answertime1"},
|
||||
utils.USAGE: &utils.RSRField{Id: "duration1"},
|
||||
"extra1": &utils.RSRField{Id: "extraval1"},
|
||||
"extra2": &utils.RSRField{Id: "extraval1"},
|
||||
eCdrcCdrFlds := map[string][]*utils.RSRField{
|
||||
utils.TOR: []*utils.RSRField{&utils.RSRField{Id: "tor1"}},
|
||||
utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "accid1"}},
|
||||
utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "reqtype1"}},
|
||||
utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "direction1"}},
|
||||
utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "tenant1"}},
|
||||
utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "category1"}},
|
||||
utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "account1"}},
|
||||
utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "subject1"}},
|
||||
utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "destination1"}},
|
||||
utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "setuptime1"}},
|
||||
utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "answertime1"}},
|
||||
utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "duration1"}},
|
||||
"extra1": []*utils.RSRField{&utils.RSRField{Id: "extraval1"}},
|
||||
"extra2": []*utils.RSRField{&utils.RSRField{Id: "extraval1"}},
|
||||
}
|
||||
if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
|
||||
t.Error("Could not parse the config", err.Error())
|
||||
|
||||
@@ -57,30 +57,30 @@ func (cdrcCfg *CgrXmlCdrcCfg) setDefaults() error {
|
||||
cdrcCfg.CdrSourceId = dfCfg.CdrcSourceId
|
||||
}
|
||||
if len(cdrcCfg.CdrFields) == 0 {
|
||||
for key, cfgRsrField := range dfCfg.CdrcCdrFields {
|
||||
cdrcCfg.CdrFields = append(cdrcCfg.CdrFields, &CdrcField{Id: key, Value: cfgRsrField.Id, rsrField: cfgRsrField})
|
||||
for key, cfgRsrFields := range dfCfg.CdrcCdrFields {
|
||||
cdrcCfg.CdrFields = append(cdrcCfg.CdrFields, &CdrcField{Id: key, Value: "PLACEHOLDER", rsrFields: cfgRsrFields})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cdrcCfg *CgrXmlCdrcCfg) CdrRSRFields() map[string]*utils.RSRField {
|
||||
rsrFields := make(map[string]*utils.RSRField)
|
||||
func (cdrcCfg *CgrXmlCdrcCfg) CdrRSRFields() map[string][]*utils.RSRField {
|
||||
rsrFields := make(map[string][]*utils.RSRField)
|
||||
for _, fld := range cdrcCfg.CdrFields {
|
||||
rsrFields[fld.Id] = fld.rsrField
|
||||
rsrFields[fld.Id] = fld.rsrFields
|
||||
}
|
||||
return rsrFields
|
||||
}
|
||||
|
||||
type CdrcField struct {
|
||||
XMLName xml.Name `xml:"field"`
|
||||
Id string `xml:"id,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
rsrField *utils.RSRField
|
||||
XMLName xml.Name `xml:"field"`
|
||||
Id string `xml:"id,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
rsrFields []*utils.RSRField
|
||||
}
|
||||
|
||||
func (cdrcFld *CdrcField) PopulateRSRField() (err error) {
|
||||
if cdrcFld.rsrField, err = utils.NewRSRField(cdrcFld.Value); err != nil {
|
||||
func (cdrcFld *CdrcField) PopulateRSRFields() (err error) {
|
||||
if cdrcFld.rsrFields, err = utils.ParseRSRFields(cdrcFld.Value, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -30,15 +30,15 @@ var cfgDocCdrc *CgrXmlCfgDocument // Will be populated by first test
|
||||
|
||||
func TestPopulateRSRFIeld(t *testing.T) {
|
||||
cdrcField := CdrcField{Id: "TEST1", Value: `~effective_caller_id_number:s/(\d+)/+$1/`}
|
||||
if err := cdrcField.PopulateRSRField(); err != nil {
|
||||
if err := cdrcField.PopulateRSRFields(); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if cdrcField.rsrField == nil {
|
||||
} else if cdrcField.rsrFields == nil {
|
||||
t.Error("Failed loading the RSRField")
|
||||
}
|
||||
cdrcField = CdrcField{Id: "TEST2", Value: `99`}
|
||||
if err := cdrcField.PopulateRSRField(); err != nil {
|
||||
if err := cdrcField.PopulateRSRFields(); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if cdrcField.rsrField == nil {
|
||||
} else if cdrcField.rsrFields == nil {
|
||||
t.Error("Failed loading the RSRField")
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func TestParseXmlCdrcConfig(t *testing.T) {
|
||||
<cdr_out_dir>/var/log/cgrates/cdrc/out</cdr_out_dir>
|
||||
<cdr_source_id>freeswitch_csv</cdr_source_id>
|
||||
<fields>
|
||||
<field id="accid" value="0" />
|
||||
<field id="accid" value="0;13" />
|
||||
<field id="reqtype" value="1" />
|
||||
<field id="direction" value="2" />
|
||||
<field id="tenant" value="3" />
|
||||
@@ -123,7 +123,7 @@ func TestGetCdrcCfgs(t *testing.T) {
|
||||
expectCdrc := &CgrXmlCdrcCfg{Enabled: true, CdrsAddress: "internal", CdrType: "csv", CsvSeparator: ",",
|
||||
RunDelay: 0, CdrInDir: "/var/log/cgrates/cdrc/in", CdrOutDir: "/var/log/cgrates/cdrc/out", CdrSourceId: "freeswitch_csv"}
|
||||
cdrFlds := []*CdrcField{
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCID, Value: "0"},
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCID, Value: "0;13"},
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.REQTYPE, Value: "1"},
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DIRECTION, Value: "2"},
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.TENANT, Value: "3"},
|
||||
@@ -137,7 +137,7 @@ func TestGetCdrcCfgs(t *testing.T) {
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr1", Value: "11"},
|
||||
&CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr2", Value: "12"}}
|
||||
for _, fld := range cdrFlds {
|
||||
fld.PopulateRSRField()
|
||||
fld.PopulateRSRFields()
|
||||
}
|
||||
expectCdrc.CdrFields = cdrFlds
|
||||
if !reflect.DeepEqual(expectCdrc, cdrcfgs["CDRC-CSV1"]) {
|
||||
@@ -150,20 +150,20 @@ func TestCdrRSRFields(t *testing.T) {
|
||||
if cdrcfgs == nil {
|
||||
t.Error("No config instance returned")
|
||||
}
|
||||
eRSRFields := map[string]*utils.RSRField{
|
||||
utils.ACCID: &utils.RSRField{Id: "0"},
|
||||
utils.REQTYPE: &utils.RSRField{Id: "1"},
|
||||
utils.DIRECTION: &utils.RSRField{Id: "2"},
|
||||
utils.TENANT: &utils.RSRField{Id: "3"},
|
||||
utils.CATEGORY: &utils.RSRField{Id: "4"},
|
||||
utils.ACCOUNT: &utils.RSRField{Id: "5"},
|
||||
utils.SUBJECT: &utils.RSRField{Id: "6"},
|
||||
utils.DESTINATION: &utils.RSRField{Id: "7"},
|
||||
utils.SETUP_TIME: &utils.RSRField{Id: "8"},
|
||||
utils.ANSWER_TIME: &utils.RSRField{Id: "9"},
|
||||
utils.USAGE: &utils.RSRField{Id: "10"},
|
||||
"extr1": &utils.RSRField{Id: "11"},
|
||||
"extr2": &utils.RSRField{Id: "12"},
|
||||
eRSRFields := map[string][]*utils.RSRField{
|
||||
utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "0"}, &utils.RSRField{Id: "13"}},
|
||||
utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "1"}},
|
||||
utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "2"}},
|
||||
utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "3"}},
|
||||
utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "4"}},
|
||||
utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "5"}},
|
||||
utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "6"}},
|
||||
utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "7"}},
|
||||
utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "8"}},
|
||||
utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "9"}},
|
||||
utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "10"}},
|
||||
"extr1": []*utils.RSRField{&utils.RSRField{Id: "11"}},
|
||||
"extr2": []*utils.RSRField{&utils.RSRField{Id: "12"}},
|
||||
}
|
||||
if rsrFields := cdrcfgs["CDRC-CSV1"].CdrRSRFields(); !reflect.DeepEqual(rsrFields, eRSRFields) {
|
||||
t.Errorf("Expecting: %v, received: %v", eRSRFields, rsrFields)
|
||||
|
||||
@@ -85,7 +85,7 @@ func (xmlCfg *CgrXmlCfgDocument) cacheCdrcCfgs() error {
|
||||
}
|
||||
// Cache rsr fields
|
||||
for _, fld := range cdrcCfg.CdrFields {
|
||||
if err := fld.PopulateRSRField(); err != nil {
|
||||
if err := fld.PopulateRSRFields(); err != nil {
|
||||
return fmt.Errorf("Populating field %s, error: %s", fld.Id, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user