Skip to content

Commit

Permalink
Clone default configured cdre and cdrc instances to avoid pointer inh…
Browse files Browse the repository at this point in the history
…eritage
  • Loading branch information
danbogos committed Jan 20, 2015
1 parent 1a02245 commit 18b90fb
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 12 deletions.
20 changes: 20 additions & 0 deletions config/cdrcconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,23 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
}
return nil
}

// Clone itself into a new CdrcConfig
func (self *CdrcConfig) Clone() *CdrcConfig {
clnCdrc := new(CdrcConfig)
clnCdrc.Enabled = self.Enabled
clnCdrc.CdrsAddress = self.CdrsAddress
clnCdrc.CdrFormat = self.CdrFormat
clnCdrc.FieldSeparator = self.FieldSeparator
clnCdrc.DataUsageMultiplyFactor = self.DataUsageMultiplyFactor
clnCdrc.RunDelay = self.RunDelay
clnCdrc.CdrInDir = self.CdrInDir
clnCdrc.CdrOutDir = self.CdrOutDir
clnCdrc.CdrSourceId = self.CdrSourceId
clnCdrc.CdrFields = make([]*CfgCdrField, len(self.CdrFields))
for idx, fld := range self.CdrFields {
clonedVal := *fld
clnCdrc.CdrFields[idx] = &clonedVal
}
return clnCdrc
}
30 changes: 30 additions & 0 deletions config/cdreconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,33 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error {
}
return nil
}

// Clone itself into a new CdreConfig
func (self *CdreConfig) Clone() *CdreConfig {
clnCdre := new(CdreConfig)
clnCdre.CdrFormat = self.CdrFormat
clnCdre.FieldSeparator = self.FieldSeparator
clnCdre.DataUsageMultiplyFactor = self.DataUsageMultiplyFactor
clnCdre.CostMultiplyFactor = self.CostMultiplyFactor
clnCdre.CostRoundingDecimals = self.CostRoundingDecimals
clnCdre.CostShiftDigits = self.CostShiftDigits
clnCdre.MaskDestId = self.MaskDestId
clnCdre.MaskLength = self.MaskLength
clnCdre.ExportDir = self.ExportDir
clnCdre.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields))
for idx, fld := range self.HeaderFields {
clonedVal := *fld
clnCdre.HeaderFields[idx] = &clonedVal
}
clnCdre.ContentFields = make([]*CfgCdrField, len(self.ContentFields))
for idx, fld := range self.ContentFields {
clonedVal := *fld
clnCdre.ContentFields[idx] = &clonedVal
}
clnCdre.TrailerFields = make([]*CfgCdrField, len(self.TrailerFields))
for idx, fld := range self.TrailerFields {
clonedVal := *fld
clnCdre.TrailerFields[idx] = &clonedVal
}
return clnCdre
}
79 changes: 79 additions & 0 deletions config/cdreconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,82 @@ 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 (
"github.com/cgrates/cgrates/utils"
"reflect"
"testing"
)

func TestCdreCfgClone(t *testing.T) {
cgrIdRsrs, _ := utils.ParseRSRFields("cgrid", utils.INFIELD_SEP)
runIdRsrs, _ := utils.ParseRSRFields("mediation_runid", utils.INFIELD_SEP)
emptyFields := []*CfgCdrField{}
initContentFlds := []*CfgCdrField{
&CfgCdrField{Tag: "CgrId",
Type: "cdrfield",
CdrFieldId: "cgrid",
Value: cgrIdRsrs},
&CfgCdrField{Tag: "RunId",
Type: "cdrfield",
CdrFieldId: "mediation_runid",
Value: runIdRsrs},
}
initCdreCfg := &CdreConfig{
CdrFormat: "csv",
FieldSeparator: rune(','),
DataUsageMultiplyFactor: 1.0,
CostMultiplyFactor: 1.0,
CostRoundingDecimals: -1,
CostShiftDigits: 0,
MaskDestId: "MASKED_DESTINATIONS",
MaskLength: 0,
ExportDir: "/var/log/cgrates/cdre",
ContentFields: initContentFlds,
}
eClnContentFlds := []*CfgCdrField{
&CfgCdrField{Tag: "CgrId",
Type: "cdrfield",
CdrFieldId: "cgrid",
Value: cgrIdRsrs},
&CfgCdrField{Tag: "RunId",
Type: "cdrfield",
CdrFieldId: "mediation_runid",
Value: runIdRsrs},
}
eClnCdreCfg := &CdreConfig{
CdrFormat: "csv",
FieldSeparator: rune(','),
DataUsageMultiplyFactor: 1.0,
CostMultiplyFactor: 1.0,
CostRoundingDecimals: -1,
CostShiftDigits: 0,
MaskDestId: "MASKED_DESTINATIONS",
MaskLength: 0,
ExportDir: "/var/log/cgrates/cdre",
HeaderFields: emptyFields,
ContentFields: eClnContentFlds,
TrailerFields: emptyFields,
}
clnCdreCfg := initCdreCfg.Clone()
if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) {
t.Errorf("Cloned result: %+v", clnCdreCfg)
}
initCdreCfg.DataUsageMultiplyFactor = 1024.0
if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance
t.Errorf("Cloned result: %+v", clnCdreCfg)
}
initContentFlds[0].Tag = "Destination"
if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance
t.Errorf("Cloned result: %+v", clnCdreCfg)
}
clnCdreCfg.CostShiftDigits = 2
if initCdreCfg.CostShiftDigits != 0 {
t.Error("Unexpected CostShiftDigits: ", initCdreCfg.CostShiftDigits)
}
clnCdreCfg.ContentFields[0].CdrFieldId = "destination"
if initCdreCfg.ContentFields[0].CdrFieldId != "cgrid" {
t.Error("Unexpected change of CdrFieldId: ", initCdreCfg.ContentFields[0].CdrFieldId)
}

}
8 changes: 6 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil {
return nil, err
}
cfg.dfltCdreProfile = cfg.CdreProfiles[utils.META_DEFAULT].Clone() // So default will stay unique, will have nil pointer in case of no defaults loaded which is an extra check
cfg.dfltCdrcProfile = cfg.CdrcProfiles[utils.META_DEFAULT].Clone()
if err := cfg.checkConfigSanity(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -169,7 +171,9 @@ type CGRConfig struct {
CDRSStoreDisable bool // When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
CDRStatsEnabled bool // Enable CDR Stats service
CDRStatConfig *CdrStatsConfig // Active cdr stats configuration instances, platform level
dfltCdreProfile *CdreConfig // Use it to cache the default cdreConfig profile, so we can clone the orginal one in separate instances
CdreProfiles map[string]*CdreConfig
dfltCdrcProfile *CdrcConfig // Use it to cache the default cdrcConfig profile
CdrcProfiles map[string]*CdrcConfig // Number of CDRC instances running imports
SMEnabled bool
SMSwitchType string
Expand Down Expand Up @@ -481,7 +485,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
if _, hasProfile := self.CdreProfiles[profileName]; !hasProfile { // New profile, create before loading from json
self.CdreProfiles[profileName] = new(CdreConfig)
if profileName != utils.META_DEFAULT {
self.CdreProfiles[profileName] = self.CdreProfiles[utils.META_DEFAULT] // Load defaults into newly initialized config
self.CdreProfiles[profileName] = self.dfltCdreProfile.Clone() // Clone default so we do not inherit pointers
}
}
if err = self.CdreProfiles[profileName].loadFromJsonCfg(jsnCdre1Cfg); err != nil { // Update the existing profile with content from json config
Expand All @@ -497,7 +501,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
if _, hasProfile := self.CdrcProfiles[profileName]; !hasProfile {
self.CdrcProfiles[profileName] = new(CdrcConfig)
if profileName != utils.META_DEFAULT {
self.CdrcProfiles[profileName] = self.CdrcProfiles[utils.META_DEFAULT] // Load defaults into newly initialized config
self.CdrcProfiles[profileName] = self.dfltCdrcProfile.Clone() // Clone default so we do not inherit pointers
}
}
if err = self.CdrcProfiles[profileName].loadFromJsonCfg(jsnCrc1Cfg); err != nil {
Expand Down
11 changes: 4 additions & 7 deletions config/multifiles_local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,13 @@ func TestMfCdreDefaultInstance(t *testing.T) {
if mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor != 1024.0 {
t.Error("Default instance has cdrFormat: ", mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor)
}
if len(mfCgrCfg.CdreProfiles[prfl].HeaderFields) != 2 {
if len(mfCgrCfg.CdreProfiles[prfl].HeaderFields) != 0 {
t.Error("Default instance has number of header fields: ", len(mfCgrCfg.CdreProfiles[prfl].HeaderFields))
}
if mfCgrCfg.CdreProfiles[prfl].HeaderFields[1].Tag != "RunId" {
t.Error("Unexpected headerField value: ", mfCgrCfg.CdreProfiles[prfl].HeaderFields[1].Tag)
}
if len(mfCgrCfg.CdreProfiles[prfl].ContentFields) != 9 {
if len(mfCgrCfg.CdreProfiles[prfl].ContentFields) != 12 {
t.Error("Default instance has number of content fields: ", len(mfCgrCfg.CdreProfiles[prfl].ContentFields))
}
if mfCgrCfg.CdreProfiles[prfl].ContentFields[2].Tag != "Account" {
if mfCgrCfg.CdreProfiles[prfl].ContentFields[2].Tag != "Direction" {
t.Error("Unexpected headerField value: ", mfCgrCfg.CdreProfiles[prfl].ContentFields[2].Tag)
}
}
Expand All @@ -89,7 +86,7 @@ func TestMfCdreExport1Instance(t *testing.T) {
t.Error("Export1 instance has cdrFormat: ", mfCgrCfg.CdreProfiles[prfl].CdrFormat)
}
if mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor != 1.0 {
t.Error("Export1 instance has cdrFormat: ", mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor)
t.Error("Export1 instance has DataUsageMultiplyFormat: ", mfCgrCfg.CdreProfiles[prfl].DataUsageMultiplyFactor)
}
if mfCgrCfg.CdreProfiles[prfl].CostRoundingDecimals != 3.0 {
t.Error("Export1 instance has cdrFormat: ", mfCgrCfg.CdreProfiles[prfl].CostRoundingDecimals)
Expand Down
3 changes: 0 additions & 3 deletions data/conf/samples/multifiles/a.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
"cdre": {
"*default": {
"content_fields": [ // template of the exported content fields
{"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"},
{"tag":"RunId", "cdr_field_id": "mediation_runid", "type": "cdrfield", "value": "mediation_runid"},
{"tag":"Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "tor"},
{"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"},
{"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"},
{"tag":"Direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "direction"},
Expand Down

0 comments on commit 18b90fb

Please sign in to comment.