mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Clone default configured cdre and cdrc instances to avoid pointer inheritage
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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"},
|
||||
|
||||
Reference in New Issue
Block a user