Correctly Copy() functions for Config struct and complete EventReader config ( + tests )

This commit is contained in:
TeoV
2019-08-13 12:07:05 +03:00
committed by Dan Christian Bogos
parent fcee9687ab
commit 400a0f506f
10 changed files with 449 additions and 13 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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))
}
}

View File

@@ -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))
}
}

View File

@@ -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
}

99
config/erscfg_test.go Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>
*/
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))
}
}

View File

@@ -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
}

View File

@@ -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))
}
}

View File

@@ -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
}