diff --git a/config/cdrccfg.go b/config/cdrccfg.go index 7b8b6fa01..5d12714eb 100644 --- a/config/cdrccfg.go +++ b/config/cdrccfg.go @@ -184,20 +184,16 @@ func (self *CdrcCfg) Clone() *CdrcCfg { clnCdrc.TrailerFields = make([]*FCTemplate, len(self.TrailerFields)) clnCdrc.CacheDumpFields = make([]*FCTemplate, len(self.CacheDumpFields)) for idx, fld := range self.HeaderFields { - clonedVal := *fld - clnCdrc.HeaderFields[idx] = &clonedVal + clnCdrc.HeaderFields[idx] = fld.Clone() } for idx, fld := range self.ContentFields { - clonedVal := *fld - clnCdrc.ContentFields[idx] = &clonedVal + clnCdrc.ContentFields[idx] = fld.Clone() } for idx, fld := range self.TrailerFields { - clonedVal := *fld - clnCdrc.TrailerFields[idx] = &clonedVal + clnCdrc.TrailerFields[idx] = fld.Clone() } for idx, fld := range self.CacheDumpFields { - clonedVal := *fld - clnCdrc.CacheDumpFields[idx] = &clonedVal + clnCdrc.CacheDumpFields[idx] = fld.Clone() } return clnCdrc } diff --git a/config/cdrccfg_test.go b/config/cdrccfg_test.go index 4d7c8ea85..da7d99f8e 100644 --- a/config/cdrccfg_test.go +++ b/config/cdrccfg_test.go @@ -123,7 +123,7 @@ func TestCdrcCfgloadFromJsonCfg(t *testing.T) { func TestCdrcCfgClone(t *testing.T) { clnCdrcCfg := *cdrcCfg.Clone() if !reflect.DeepEqual(cdrcCfg, clnCdrcCfg) { - t.Errorf("Expected: %+v , recived: %+v", cdrcCfg, clnCdrcCfg) + t.Errorf("Expected: %+v ,\n recived: %+v", utils.ToJSON(cdrcCfg), utils.ToJSON(clnCdrcCfg)) } cdrcCfg.ContentFields[0].Tag = "CGRID" if reflect.DeepEqual(cdrcCfg, clnCdrcCfg) { // MOdifying a field after clone should not affect cloned instance diff --git a/config/config.go b/config/config.go index d3108eef1..78803e656 100755 --- a/config/config.go +++ b/config/config.go @@ -169,6 +169,7 @@ func NewDefaultCGRConfig() (*CGRConfig, error) { cfg.loaderCfg = make([]*LoaderSCfg, 0) cfg.SmOsipsConfig = new(SmOsipsConfig) cfg.apier = new(ApierCfg) + cfg.erCfg = new(ERsCfg) cfg.ConfigReloads = make(map[string]chan struct{}) cfg.ConfigReloads[utils.CDRC] = make(chan struct{}, 1) @@ -351,6 +352,7 @@ type CGRConfig struct { analyzerSCfg *AnalyzerSCfg // AnalyzerS config SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration apier *ApierCfg + erCfg *ERsCfg } var posibleLoaderTypes = utils.NewStringSet([]string{utils.MetaAttributes, @@ -1009,6 +1011,13 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { if err := self.apier.loadFromJsonCfg(jsnApierCfg); err != nil { return err } + jsnERsCfg, err := jsnCfg.ERsJsonCfg() + if err != nil { + return nil + } + if err := self.erCfg.loadFromJsonCfg(jsnERsCfg, self.generalCfg.RsrSepatarot); err != nil { + return err + } if jsnCdreCfg != nil { for profileName, jsnCdre1Cfg := range jsnCdreCfg { @@ -1218,6 +1227,10 @@ func (cfg *CGRConfig) ApierCfg() *ApierCfg { return cfg.apier } +func (cfg *CGRConfig) ERsCfg() *ERsCfg { + return cfg.erCfg +} + // Call implements rpcclient.RpcClientConnection interface for internal RPC func (cSv1 *CGRConfig) Call(serviceMethod string, args interface{}, reply interface{}) error { diff --git a/config/config_json_test.go b/config/config_json_test.go index a45db42c6..e27fd3e34 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -1582,3 +1582,64 @@ func TestDfApierCfg(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", utils.ToJSON(eCfg), utils.ToJSON(cfg)) } } + +func TestDfEventReaderCfg(t *testing.T) { + cdrFields := []*FcTemplateJsonCfg{ + {Tag: utils.StringPointer("TOR"), Field_id: utils.StringPointer(utils.ToR), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~2"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("OriginID"), Field_id: utils.StringPointer(utils.OriginID), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~3"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("RequestType"), Field_id: utils.StringPointer(utils.RequestType), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~4"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("Tenant"), Field_id: utils.StringPointer(utils.Tenant), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~6"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("Category"), Field_id: utils.StringPointer(utils.Category), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~7"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("Account"), Field_id: utils.StringPointer(utils.Account), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~8"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("Subject"), Field_id: utils.StringPointer(utils.Subject), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~9"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("Destination"), Field_id: utils.StringPointer(utils.Destination), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~10"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("SetupTime"), Field_id: utils.StringPointer(utils.SetupTime), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~11"), Mandatory: utils.BoolPointer(true)}, + {Tag: utils.StringPointer("AnswerTime"), Field_id: utils.StringPointer(utils.AnswerTime), Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer("~12"), Mandatory: utils.BoolPointer(true)}, + {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 := &ERsJsonCfg{ + Enabled: utils.BoolPointer(false), + Sessions_conns: &[]*RemoteHostJson{ + { + Address: utils.StringPointer(utils.MetaInternal), + }, + }, + Readers: &[]*EventReaderJsonCfg{ + &EventReaderJsonCfg{ + Id: utils.StringPointer(utils.MetaDefault), + Type: utils.StringPointer(utils.MetaFileCSV), + Field_separator: utils.StringPointer(","), + Run_delay: utils.IntPointer(0), + Concurrent_requests: utils.IntPointer(1024), + Source_path: utils.StringPointer("/var/spool/cgrates/cdrc/in"), + Processed_path: utils.StringPointer("/var/spool/cgrates/cdrc/out"), + Xml_root_path: utils.StringPointer(utils.EmptyString), + Source_id: utils.StringPointer("ers_csv"), + Tenant: utils.StringPointer(utils.EmptyString), + Timezone: utils.StringPointer(utils.EmptyString), + Filters: &[]string{}, + Flags: &[]string{}, + Header_fields: &[]*FcTemplateJsonCfg{}, + Content_fields: &cdrFields, + Trailer_fields: &[]*FcTemplateJsonCfg{}, + Continue: utils.BoolPointer(false), + }, + }, + } + if cfg, err := dfCgrJsonCfg.ERsJsonCfg(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eCfg, cfg) { + t.Errorf("Expected: %+v, \nreceived: %+v", utils.ToJSON(eCfg), utils.ToJSON(cfg)) + } +} diff --git a/config/config_test.go b/config/config_test.go index 24237671f..a99187f3b 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -1801,3 +1801,60 @@ func TestCgrCfgV1GetConfigSection(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", expected, rcv) } } + +func TestCgrCdfEventReader(t *testing.T) { + eCfg := &ERsCfg{ + Enabled: false, + SessionSConns: []*RemoteHost{ + { + Address: utils.MetaInternal, + }, + }, + Readers: []*EventReaderCfg{ + &EventReaderCfg{ + ID: utils.MetaDefault, + Type: utils.MetaFileCSV, + FieldSep: ",", + RunDelay: time.Duration(0), + ConcurrentReqs: 1024, + SourcePath: "/var/spool/cgrates/cdrc/in", + ProcessedPath: "/var/spool/cgrates/cdrc/out", + XmlRootPath: utils.EmptyString, + SourceID: "ers_csv", + Tenant: NewRSRParsersMustCompile("", true, utils.INFIELD_SEP), + Timezone: utils.EmptyString, + Filters: []string{}, + Flags: utils.FlagsWithParams{}, + Header_fields: make([]*FCTemplate, 0), + Content_fields: []*FCTemplate{ + {Tag: "TOR", FieldId: "ToR", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~2", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "OriginID", FieldId: "OriginID", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~3", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "RequestType", FieldId: "RequestType", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~4", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Tenant", FieldId: "Tenant", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~6", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Category", FieldId: "Category", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~7", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Account", FieldId: "Account", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~8", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Subject", FieldId: "Subject", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~9", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Destination", FieldId: "Destination", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~10", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "SetupTime", FieldId: "SetupTime", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~11", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "AnswerTime", FieldId: "AnswerTime", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~12", true, utils.INFIELD_SEP), Mandatory: true}, + {Tag: "Usage", FieldId: "Usage", Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("~13", true, utils.INFIELD_SEP), Mandatory: true}, + }, + Trailer_fields: make([]*FCTemplate, 0), + }, + }, + } + if !reflect.DeepEqual(cgrCfg.erCfg, eCfg) { + t.Errorf("received: %+v,\n expecting: %+v", utils.ToJSON(cgrCfg.erCfg), utils.ToJSON(eCfg)) + } +} diff --git a/config/erscfg.go b/config/erscfg.go index 0e8acf1ce..976fa5ef2 100644 --- a/config/erscfg.go +++ b/config/erscfg.go @@ -30,18 +30,52 @@ type ERsCfg struct { Readers []*EventReaderCfg } -func (erS *ERsJsonCfg) loadFromJsonCfg(jsnCfg *ERsJsonCfg, sep string) (err error) { +func (erS *ERsCfg) loadFromJsonCfg(jsnCfg *ERsJsonCfg, sep string) (err error) { if jsnCfg == nil { return } + if jsnCfg.Enabled != nil { + erS.Enabled = *jsnCfg.Enabled + } + if jsnCfg.Sessions_conns != nil { + erS.SessionSConns = make([]*RemoteHost, len(*jsnCfg.Sessions_conns)) + for idx, jsnHaCfg := range *jsnCfg.Sessions_conns { + erS.SessionSConns[idx] = NewDfltRemoteHost() + erS.SessionSConns[idx].loadFromJsonCfg(jsnHaCfg) + } + } + if jsnCfg.Readers != nil { + erS.Readers = make([]*EventReaderCfg, len(*jsnCfg.Readers)) + for idx, rdrs := range *jsnCfg.Readers { + erS.Readers[idx] = NewDfltEventReaderCfg() + if err = erS.Readers[idx].loadFromJsonCfg(rdrs, sep); err != nil { + return err + } + } + } return } // Clone itself into a new ERsCfg func (erS *ERsCfg) Clone() (cln *ERsCfg) { + cln = new(ERsCfg) + cln.Enabled = erS.Enabled + cln.SessionSConns = make([]*RemoteHost, len(erS.SessionSConns)) + for idx, sConn := range erS.SessionSConns { + clonedVal := *sConn + cln.SessionSConns[idx] = &clonedVal + } + cln.Readers = make([]*EventReaderCfg, len(erS.Readers)) + for idx, rdr := range erS.Readers { + cln.Readers[idx] = rdr.Clone() + } return } +func NewDfltEventReaderCfg() *EventReaderCfg { + return new(EventReaderCfg) +} + type EventReaderCfg struct { ID string Type string @@ -51,9 +85,9 @@ type EventReaderCfg struct { SourcePath string ProcessedPath string XmlRootPath string + SourceID string Tenant RSRParsers Timezone string - SourceID string Filters []string Flags utils.FlagsWithParams Header_fields []*FCTemplate @@ -66,5 +100,110 @@ func (er *EventReaderCfg) loadFromJsonCfg(jsnCfg *EventReaderJsonCfg, sep string if jsnCfg == nil { return } + if jsnCfg.Id != nil { + er.ID = *jsnCfg.Id + } + if jsnCfg.Type != nil { + er.Type = *jsnCfg.Type + } + if jsnCfg.Field_separator != nil { + er.FieldSep = *jsnCfg.Field_separator + } + if jsnCfg.Run_delay != nil { + er.RunDelay = time.Duration(*jsnCfg.Run_delay) + } + if jsnCfg.Concurrent_requests != nil { + er.ConcurrentReqs = *jsnCfg.Concurrent_requests + } + if jsnCfg.Source_path != nil { + er.SourcePath = *jsnCfg.Source_path + } + if jsnCfg.Processed_path != nil { + er.ProcessedPath = *jsnCfg.Processed_path + } + if jsnCfg.Xml_root_path != nil { + er.XmlRootPath = *jsnCfg.Xml_root_path + } + if jsnCfg.Source_id != nil { + er.SourceID = *jsnCfg.Source_id + } + if jsnCfg.Tenant != nil { + if er.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, true, sep); err != nil { + return err + } + } + if jsnCfg.Timezone != nil { + er.Timezone = *jsnCfg.Timezone + } + if jsnCfg.Filters != nil { + er.Filters = make([]string, len(*jsnCfg.Filters)) + for i, fltr := range *jsnCfg.Filters { + er.Filters[i] = fltr + } + } + if jsnCfg.Flags != nil { + if er.Flags, err = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags); err != nil { + return + } + } + if jsnCfg.Header_fields != nil { + if er.Header_fields, err = FCTemplatesFromFCTemplatesJsonCfg(*jsnCfg.Header_fields, sep); err != nil { + return err + } + } + if jsnCfg.Content_fields != nil { + if er.Content_fields, err = FCTemplatesFromFCTemplatesJsonCfg(*jsnCfg.Content_fields, sep); err != nil { + return err + } + } + if jsnCfg.Trailer_fields != nil { + if er.Trailer_fields, err = FCTemplatesFromFCTemplatesJsonCfg(*jsnCfg.Trailer_fields, sep); err != nil { + return err + } + } + if jsnCfg.Continue != nil { + er.Continue = *jsnCfg.Continue + } + return +} + +//Clone itself into a new EventReaderCfg +func (er *EventReaderCfg) Clone() (cln *EventReaderCfg) { + cln = new(EventReaderCfg) + cln.ID = er.ID + cln.Type = er.Type + cln.FieldSep = er.FieldSep + cln.RunDelay = er.RunDelay + cln.ConcurrentReqs = er.ConcurrentReqs + cln.SourcePath = er.SourcePath + cln.ProcessedPath = er.ProcessedPath + cln.XmlRootPath = er.XmlRootPath + cln.SourceID = er.SourceID + cln.Tenant = make(RSRParsers, len(er.Tenant)) + for idx, val := range er.Tenant { + clnVal := *val + cln.Tenant[idx] = &clnVal + } + cln.Timezone = er.Timezone + if len(er.Filters) != 0 { + cln.Filters = make([]string, len(er.Filters)) + for idx, val := range er.Filters { + cln.Filters[idx] = val + } + } + cln.Flags = er.Flags + cln.Header_fields = make([]*FCTemplate, len(er.Header_fields)) + for idx, fld := range er.Header_fields { + cln.Header_fields[idx] = fld.Clone() + } + cln.Content_fields = make([]*FCTemplate, len(er.Content_fields)) + for idx, fld := range er.Content_fields { + cln.Content_fields[idx] = fld.Clone() + } + cln.Trailer_fields = make([]*FCTemplate, len(er.Trailer_fields)) + for idx, fld := range er.Trailer_fields { + cln.Trailer_fields[idx] = fld.Clone() + } + cln.Continue = er.Continue return } diff --git a/config/erscfg_test.go b/config/erscfg_test.go new file mode 100644 index 000000000..a77f4dbbb --- /dev/null +++ b/config/erscfg_test.go @@ -0,0 +1,99 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package config + +import ( + "reflect" + "testing" + + "github.com/cgrates/cgrates/utils" +) + +func TestEventRedearClone(t *testing.T) { + orig := &EventReaderCfg{ + ID: utils.MetaDefault, + Type: "RandomType", + FieldSep: ",", + SourceID: "RandomSource", + Filters: []string{"Filter1", "Filter2"}, + Tenant: NewRSRParsersMustCompile("cgrates.org", true, utils.INFIELD_SEP), + Header_fields: []*FCTemplate{}, + Content_fields: []*FCTemplate{ + { + Tag: "TOR", + FieldId: "ToR", + Type: "*composed", + Value: NewRSRParsersMustCompile("~2", true, utils.INFIELD_SEP), + Mandatory: true, + }, + { + Tag: "RandomField", + FieldId: "RandomField", + Type: "*composed", + Value: NewRSRParsersMustCompile("Test", true, utils.INFIELD_SEP), + Mandatory: true, + }, + }, + Trailer_fields: []*FCTemplate{}, + Continue: true, + } + cloned := orig.Clone() + if !reflect.DeepEqual(cloned, orig) { + t.Errorf("expected: %s ,received: %s", utils.ToJSON(orig), utils.ToJSON(cloned)) + } + initialOrig := &EventReaderCfg{ + ID: utils.MetaDefault, + Type: "RandomType", + FieldSep: ",", + SourceID: "RandomSource", + Filters: []string{"Filter1", "Filter2"}, + Tenant: NewRSRParsersMustCompile("cgrates.org", true, utils.INFIELD_SEP), + Header_fields: []*FCTemplate{}, + Content_fields: []*FCTemplate{ + { + Tag: "TOR", + FieldId: "ToR", + Type: "*composed", + Value: NewRSRParsersMustCompile("~2", true, utils.INFIELD_SEP), + Mandatory: true, + }, + { + Tag: "RandomField", + FieldId: "RandomField", + Type: "*composed", + Value: NewRSRParsersMustCompile("Test", true, utils.INFIELD_SEP), + Mandatory: true, + }, + }, + Trailer_fields: []*FCTemplate{}, + Continue: true, + } + orig.Filters = []string{"SingleFilter"} + orig.Content_fields = []*FCTemplate{ + { + Tag: "TOR", + FieldId: "ToR", + Type: "*composed", + Value: NewRSRParsersMustCompile("~2", true, utils.INFIELD_SEP), + Mandatory: true, + }, + } + if !reflect.DeepEqual(cloned, initialOrig) { + t.Errorf("expected: %s ,received: %s", utils.ToJSON(initialOrig), utils.ToJSON(cloned)) + } +} diff --git a/config/fctemplate.go b/config/fctemplate.go index 7b95bc824..e73cc9c8d 100755 --- a/config/fctemplate.go +++ b/config/fctemplate.go @@ -161,3 +161,37 @@ func InflateTemplates(fcts []*FCTemplate, msgTpls map[string][]*FCTemplate) ([]* } return fcts, nil } + +func (self *FCTemplate) Clone() *FCTemplate { + cln := new(FCTemplate) + cln.Tag = self.Tag + cln.Type = self.Type + cln.FieldId = self.FieldId + if len(self.Filters) != 0 { + cln.Filters = make([]string, len(self.Filters)) + for idx, val := range self.Filters { + cln.Filters[idx] = val + } + } + cln.Value = make(RSRParsers, len(self.Value)) + for idx, val := range self.Value { + clnVal := *val + cln.Value[idx] = &clnVal + } + cln.Width = self.Width + cln.Strip = self.Strip + cln.Padding = self.Padding + cln.Mandatory = self.Mandatory + cln.AttributeID = self.AttributeID + cln.NewBranch = self.NewBranch + cln.Timezone = self.Timezone + cln.Blocker = self.Blocker + cln.BreakOnSuccess = self.BreakOnSuccess + cln.HandlerId = self.HandlerId + cln.Layout = self.Layout + cln.CostShiftDigits = self.CostShiftDigits + cln.RoundingDecimals = self.RoundingDecimals + cln.MaskDestID = self.MaskDestID + cln.MaskLen = self.MaskLen + return cln +} diff --git a/config/fctemplate_test.go b/config/fctemplate_test.go index 0e5af8906..b88fc1c9e 100755 --- a/config/fctemplate_test.go +++ b/config/fctemplate_test.go @@ -289,3 +289,29 @@ func TestFCTemplateInflate3(t *testing.T) { t.Error(err) } } + +func TestFCTemplateClone(t *testing.T) { + smpl := &FCTemplate{ + Tag: "Tenant", + Type: "*composed", + FieldId: "Tenant", + Filters: []string{"Filter1", "Filter2"}, + Value: NewRSRParsersMustCompile("cgrates.org", true, utils.INFIELD_SEP), + } + cloned := smpl.Clone() + if !reflect.DeepEqual(cloned, smpl) { + t.Errorf("expected: %s ,received: %s", utils.ToJSON(smpl), utils.ToJSON(cloned)) + } + initialSmpl := &FCTemplate{ + Tag: "Tenant", + Type: "*composed", + FieldId: "Tenant", + Filters: []string{"Filter1", "Filter2"}, + Value: NewRSRParsersMustCompile("cgrates.org", true, utils.INFIELD_SEP), + } + smpl.Filters = []string{"SingleFilter"} + smpl.Value = NewRSRParsersMustCompile("cgrates.com", true, utils.INFIELD_SEP) + if !reflect.DeepEqual(cloned, initialSmpl) { + t.Errorf("expected: %s ,received: %s", utils.ToJSON(initialSmpl), utils.ToJSON(cloned)) + } +} diff --git a/config/loaderscfg.go b/config/loaderscfg.go index 7787f4eb1..bbff10e23 100644 --- a/config/loaderscfg.go +++ b/config/loaderscfg.go @@ -129,6 +129,18 @@ func (self *LoaderSCfg) loadFromJsonCfg(jsnCfg *LoaderJsonCfg, separator string) return nil } +// Clone itself into a new LoaderDataType +func (self *LoaderDataType) Clone() *LoaderDataType { + cln := new(LoaderDataType) + cln.Type = self.Type + cln.Filename = self.Filename + cln.Fields = make([]*FCTemplate, len(self.Fields)) + for idx, val := range self.Fields { + cln.Fields[idx] = val.Clone() + } + return cln +} + // Clone itself into a new LoadersConfig func (self *LoaderSCfg) Clone() *LoaderSCfg { clnLoader := new(LoaderSCfg) @@ -148,8 +160,7 @@ func (self *LoaderSCfg) Clone() *LoaderSCfg { clnLoader.TpOutDir = self.TpOutDir clnLoader.Data = make([]*LoaderDataType, len(self.Data)) for idx, fld := range self.Data { - clonedVal := *fld - clnLoader.Data[idx] = &clonedVal + clnLoader.Data[idx] = fld.Clone() } return clnLoader }