From f158b191f3be03a30f1bea4125e2405897a9f080 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 25 Nov 2020 13:20:24 +0200 Subject: [PATCH] Added Clone functions for all config sections --- agents/diam_it_test.go | 2 +- agents/diamagent.go | 2 +- agents/httpagent_it_test.go | 10 +- cmd/cgr-loader/cgr-loader_it_test.go | 2 +- config/cachecfg.go | 27 +- config/cdrscfg.go | 124 +++++--- config/cdrscfg_test.go | 50 +++- config/config.go | 108 +++++-- config/config_it_test.go | 8 +- config/config_test.go | 187 ++++++++++-- config/configsanity_test.go | 6 +- config/datadbcfg.go | 50 ++-- config/datadbcfg_test.go | 32 +-- config/diametercfg.go | 91 ++++-- config/diametercfg_test.go | 43 ++- config/dnsagentcfg_test.go | 32 +++ config/dnsagntcfg.go | 30 +- config/eescfg.go | 4 +- config/eescfg_test.go | 23 +- config/filterscfg.go | 54 ++-- config/filterscfg_test.go | 23 +- config/generalcfg.go | 56 +++- config/generalcfg_test.go | 50 +++- config/httpagntcfg.go | 95 ++++-- config/httpagntcfg_test.go | 85 ++++-- config/httpcfg.go | 60 ++-- config/httpcfg_test.go | 29 +- config/kamagentcfg.go | 73 +++-- config/kamagentcfg_test.go | 30 +- config/listencfg.go | 24 +- config/listencfg_test.go | 20 +- config/loaderscfg.go | 132 +++++---- config/loaderscfg_test.go | 54 +++- config/multifiles_it_test.go | 6 +- config/radiuscfg.go | 98 ++++--- config/radiuscfg_test.go | 62 +++- config/ralscfg.go | 101 ++++--- config/ralscfg_test.go | 57 +++- config/rjreader.go | 45 +-- config/rjreader_test.go | 4 +- config/rpcconn.go | 78 +++-- config/rpcconn_test.go | 44 ++- config/schedulercfg.go | 61 ++-- config/schedulercfg_test.go | 26 ++ config/sessionscfg.go | 414 ++++++++++++++++++--------- config/sessionscfg_test.go | 184 ++++++++++-- config/stordbcfg.go | 63 ++-- config/stordbcfg_test.go | 69 ++++- config/tlscfg.go | 22 +- config/tlscfg_test.go | 23 +- loaders/loader.go | 2 +- loaders/loaders.go | 4 +- migrator/rateprofiles_it_test.go | 13 +- services/httpagent.go | 2 +- sessions/sessions.go | 40 +-- sessions/sessions_test.go | 250 ++++++++-------- 56 files changed, 2356 insertions(+), 928 deletions(-) diff --git a/agents/diam_it_test.go b/agents/diam_it_test.go index 24fc208fa..5f0f8c6c8 100644 --- a/agents/diam_it_test.go +++ b/agents/diam_it_test.go @@ -224,7 +224,7 @@ func testDiamItStartEngine(t *testing.T) { func testDiamItConnectDiameterClient(t *testing.T) { diamClnt, err = NewDiameterClient(daCfg.DiameterAgentCfg().Listen, "INTEGRATION_TESTS", - daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorId, + daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorID, daCfg.DiameterAgentCfg().ProductName, utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DictionariesPath, daCfg.DiameterAgentCfg().ListenNet) if err != nil { diff --git a/agents/diamagent.go b/agents/diamagent.go index 129062bc1..d6f72053e 100644 --- a/agents/diamagent.go +++ b/agents/diamagent.go @@ -126,7 +126,7 @@ func (da *DiameterAgent) handlers() diam.Handler { settings := &sm.Settings{ OriginHost: datatype.DiameterIdentity(da.cgrCfg.DiameterAgentCfg().OriginHost), OriginRealm: datatype.DiameterIdentity(da.cgrCfg.DiameterAgentCfg().OriginRealm), - VendorID: datatype.Unsigned32(da.cgrCfg.DiameterAgentCfg().VendorId), + VendorID: datatype.Unsigned32(da.cgrCfg.DiameterAgentCfg().VendorID), ProductName: datatype.UTF8String(da.cgrCfg.DiameterAgentCfg().ProductName), FirmwareRevision: datatype.Unsigned32(utils.DIAMETER_FIRMWARE_REVISION), } diff --git a/agents/httpagent_it_test.go b/agents/httpagent_it_test.go index ec75184b9..15461379e 100644 --- a/agents/httpagent_it_test.go +++ b/agents/httpagent_it_test.go @@ -195,7 +195,7 @@ func testHAitAuthDryRun(t *testing.T) { httpConst = "https" } reqUrl := fmt.Sprintf("%s://%s%s?request_type=OutboundAUTH&CallID=123456&Msisdn=497700056231&Imsi=2343000000000123&Destination=491239440004&MSRN=0102220233444488999&ProfileID=1&AgentID=176&GlobalMSISDN=497700056129&GlobalIMSI=214180000175129&ICCID=8923418450000089629&MCC=234&MNC=10&calltype=callback", - httpConst, addr, haCfg.HTTPAgentCfg()[0].Url) + httpConst, addr, haCfg.HTTPAgentCfg()[0].URL) rply, err := httpC.Get(reqUrl) if err != nil { t.Fatal(err) @@ -245,7 +245,7 @@ func testHAitAuth1001(t *testing.T) { } reqUrl := fmt.Sprintf("%s://%s%s?request_type=OutboundAUTH&CallID=123456&Msisdn=%s&Imsi=2343000000000123&Destination=1002&MSRN=0102220233444488999&ProfileID=1&AgentID=176&GlobalMSISDN=497700056129&GlobalIMSI=214180000175129&ICCID=8923418450000089629&MCC=234&MNC=10&calltype=callback", - httpConst, addr, haCfg.HTTPAgentCfg()[0].Url, acnt) + httpConst, addr, haCfg.HTTPAgentCfg()[0].URL, acnt) rply, err := httpC.Get(reqUrl) if err != nil { t.Fatal(err) @@ -272,7 +272,7 @@ func testHAitCDRmtcall(t *testing.T) { httpConst = "https" } reqUrl := fmt.Sprintf("%s://%s%s?request_type=MTCALL_CDR×tamp=2018-08-14%%2012:03:22&call_date=2018-0814%%2012:00:49&transactionid=10000&CDR_ID=123456&carrierid=1&mcc=0&mnc=0&imsi=434180000000000&msisdn=1001&destination=1002&leg=C&leg_duration=185&reseller_charge=11.1605&client_charge=0.0000&user_charge=22.0000&IOT=0&user_balance=10.00&cli=%%2B498702190000&polo=0.0100&ddi_map=N", - httpConst, addr, haCfg.HTTPAgentCfg()[0].Url) + httpConst, addr, haCfg.HTTPAgentCfg()[0].URL) rply, err := httpC.Get(reqUrl) if err != nil { t.Fatal(err) @@ -316,7 +316,7 @@ func testHAitCDRmtcall2(t *testing.T) { addr = haCfg.ListenCfg().HTTPTLSListen httpConst = "https" } - url := fmt.Sprintf("%s://%s%s", httpConst, addr, haCfg.HTTPAgentCfg()[1].Url) + url := fmt.Sprintf("%s://%s%s", httpConst, addr, haCfg.HTTPAgentCfg()[1].URL) req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(xmlBody))) if err != nil { @@ -351,7 +351,7 @@ func testHAitTextPlain(t *testing.T) { httpConst = "https" } reqUrl := fmt.Sprintf("%s://%s%s?request_type=TextPlainDryRun&CallID=123456&Msisdn=497700056231&Imsi=2343000000000123&Destination=491239440004", - httpConst, addr, haCfg.HTTPAgentCfg()[2].Url) + httpConst, addr, haCfg.HTTPAgentCfg()[2].URL) rply, err := httpC.Get(reqUrl) if err != nil { t.Fatal(err) diff --git a/cmd/cgr-loader/cgr-loader_it_test.go b/cmd/cgr-loader/cgr-loader_it_test.go index a4482eb38..24ff570be 100644 --- a/cmd/cgr-loader/cgr-loader_it_test.go +++ b/cmd/cgr-loader/cgr-loader_it_test.go @@ -156,7 +156,7 @@ func TestLoadConfig(t *testing.T) { if !reflect.DeepEqual(ldrCfg.LoaderCgrCfg().SchedulerConns, expAddrs) { t.Errorf("Expected %v received %v", expAddrs, ldrCfg.LoaderCgrCfg().SchedulerConns) } - expaddr := config.RpcConns{ + expaddr := config.RPCConns{ utils.MetaInternal: { Strategy: rpcclient.PoolFirst, PoolSize: 0, diff --git a/config/cachecfg.go b/config/cachecfg.go index 7ce15cacd..b141a4717 100644 --- a/config/cachecfg.go +++ b/config/cachecfg.go @@ -141,31 +141,24 @@ func (cCfg *CacheCfg) AddTmpCaches() { // AsMapInterface returns the config as a map[string]interface{} func (cCfg *CacheCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = make(map[string]interface{}) - if cCfg.Partitions != nil { - partitions := make(map[string]interface{}, len(cCfg.Partitions)) - for key, value := range cCfg.Partitions { - partitions[key] = value.AsMapInterface() - } - initialMP[utils.PartitionsCfg] = partitions + partitions := make(map[string]interface{}, len(cCfg.Partitions)) + for key, value := range cCfg.Partitions { + partitions[key] = value.AsMapInterface() } + initialMP[utils.PartitionsCfg] = partitions if cCfg.ReplicationConns != nil { - replicationConns := make([]string, len(cCfg.ReplicationConns)) - for i, item := range cCfg.ReplicationConns { - replicationConns[i] = item - } - initialMP[utils.RplConnsCfg] = replicationConns + initialMP[utils.RplConnsCfg] = cCfg.ReplicationConns } return } // Clone returns a deep copy of CacheCfg func (cCfg CacheCfg) Clone() (cln *CacheCfg) { - cln = new(CacheCfg) - if cCfg.Partitions != nil { - cln.Partitions = make(map[string]*CacheParamCfg) - for key, par := range cCfg.Partitions { - cln.Partitions[key] = par.Clone() - } + cln = &CacheCfg{ + Partitions: make(map[string]*CacheParamCfg), + } + for key, par := range cCfg.Partitions { + cln.Partitions[key] = par.Clone() } if cCfg.ReplicationConns != nil { cln.ReplicationConns = make([]string, len(cCfg.ReplicationConns)) diff --git a/config/cdrscfg.go b/config/cdrscfg.go index b4f9ed284..98087b22e 100644 --- a/config/cdrscfg.go +++ b/config/cdrscfg.go @@ -19,11 +19,10 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) +// CdrsCfg is the CDR server type CdrsCfg struct { Enabled bool // Enable CDR Server service ExtraFields RSRParsers // Extra fields to store in CDRs @@ -39,8 +38,8 @@ type CdrsCfg struct { EEsConns []string } -//loadFromJsonCfg loads Cdrs config from JsonCfg -func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { +// loadFromJSONCfg loads Cdrs config from JsonCfg +func (cdrscfg *CdrsCfg) loadFromJSONCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { if jsnCdrsCfg == nil { return nil } @@ -62,10 +61,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.ChargerSConns = make([]string, len(*jsnCdrsCfg.Chargers_conns)) for idx, connID := range *jsnCdrsCfg.Chargers_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.ChargerSConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.ChargerSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers) - } else { - cdrscfg.ChargerSConns[idx] = connID } } } @@ -73,10 +71,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.RaterConns = make([]string, len(*jsnCdrsCfg.Rals_conns)) for idx, connID := range *jsnCdrsCfg.Rals_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.RaterConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.RaterConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder) - } else { - cdrscfg.RaterConns[idx] = connID } } } @@ -84,10 +81,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.AttributeSConns = make([]string, len(*jsnCdrsCfg.Attributes_conns)) for idx, connID := range *jsnCdrsCfg.Attributes_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.AttributeSConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.AttributeSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) - } else { - cdrscfg.AttributeSConns[idx] = connID } } } @@ -95,10 +91,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.ThresholdSConns = make([]string, len(*jsnCdrsCfg.Thresholds_conns)) for idx, connID := range *jsnCdrsCfg.Thresholds_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.ThresholdSConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.ThresholdSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } else { - cdrscfg.ThresholdSConns[idx] = connID } } } @@ -106,10 +101,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.StatSConns = make([]string, len(*jsnCdrsCfg.Stats_conns)) for idx, connID := range *jsnCdrsCfg.Stats_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.StatSConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) - } else { - cdrscfg.StatSConns[idx] = connID } } } @@ -122,10 +116,9 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.SchedulerConns = make([]string, len(*jsnCdrsCfg.Scheduler_conns)) for idx, connID := range *jsnCdrsCfg.Scheduler_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.SchedulerConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.SchedulerConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler) - } else { - cdrscfg.SchedulerConns[idx] = connID } } } @@ -134,16 +127,16 @@ func (cdrscfg *CdrsCfg) loadFromJsonCfg(jsnCdrsCfg *CdrsJsonCfg) (err error) { cdrscfg.EEsConns = make([]string, len(*jsnCdrsCfg.Ees_conns)) for idx, connID := range *jsnCdrsCfg.Ees_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + cdrscfg.EEsConns[idx] = connID if connID == utils.MetaInternal { cdrscfg.EEsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs) - } else { - cdrscfg.EEsConns[idx] = connID } } } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: cdrscfg.Enabled, @@ -166,10 +159,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.ChargerSConns != nil { chargerSConns := make([]string, len(cdrscfg.ChargerSConns)) for i, item := range cdrscfg.ChargerSConns { + chargerSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers) { - chargerSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaChargers) - } else { - chargerSConns[i] = item + chargerSConns[i] = utils.MetaInternal } } initialMP[utils.ChargerSConnsCfg] = chargerSConns @@ -177,10 +169,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.RaterConns != nil { raterConns := make([]string, len(cdrscfg.RaterConns)) for i, item := range cdrscfg.RaterConns { + raterConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder) { - raterConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaResponder) - } else { - raterConns[i] = item + raterConns[i] = utils.MetaInternal } } initialMP[utils.RALsConnsCfg] = raterConns @@ -188,10 +179,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.AttributeSConns != nil { attributeSConns := make([]string, len(cdrscfg.AttributeSConns)) for i, item := range cdrscfg.AttributeSConns { + attributeSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) { - attributeSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaAttributes) - } else { - attributeSConns[i] = item + attributeSConns[i] = utils.MetaInternal } } initialMP[utils.AttributeSConnsCfg] = attributeSConns @@ -199,10 +189,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.ThresholdSConns != nil { thresholdSConns := make([]string, len(cdrscfg.ThresholdSConns)) for i, item := range cdrscfg.ThresholdSConns { + thresholdSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { - thresholdSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaThresholds) - } else { - thresholdSConns[i] = item + thresholdSConns[i] = utils.MetaInternal } } initialMP[utils.ThresholdSConnsCfg] = thresholdSConns @@ -210,10 +199,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.StatSConns != nil { statSConns := make([]string, len(cdrscfg.StatSConns)) for i, item := range cdrscfg.StatSConns { + statSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) { - statSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaStatS) - } else { - statSConns[i] = item + statSConns[i] = utils.MetaInternal } } initialMP[utils.StatSConnsCfg] = statSConns @@ -221,10 +209,9 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.SchedulerConns != nil { schedulerConns := make([]string, len(cdrscfg.SchedulerConns)) for i, item := range cdrscfg.SchedulerConns { + schedulerConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler) { - schedulerConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaScheduler) - } else { - schedulerConns[i] = item + schedulerConns[i] = utils.MetaInternal } } initialMP[utils.SchedulerConnsCfg] = schedulerConns @@ -232,13 +219,72 @@ func (cdrscfg *CdrsCfg) AsMapInterface() (initialMP map[string]interface{}) { if cdrscfg.EEsConns != nil { eesConns := make([]string, len(cdrscfg.EEsConns)) for i, item := range cdrscfg.EEsConns { + eesConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs) { - eesConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaEEs) - } else { - eesConns[i] = item + eesConns[i] = utils.MetaInternal } } initialMP[utils.EEsConnsCfg] = eesConns } return } + +// Clone returns a deep copy of CdrsCfg +func (cdrscfg CdrsCfg) Clone() (cln *CdrsCfg) { + cln = &CdrsCfg{ + Enabled: cdrscfg.Enabled, + ExtraFields: cdrscfg.ExtraFields.Clone(), + StoreCdrs: cdrscfg.StoreCdrs, + SMCostRetries: cdrscfg.SMCostRetries, + } + if cdrscfg.ChargerSConns != nil { + cln.ChargerSConns = make([]string, len(cdrscfg.ChargerSConns)) + for i, con := range cdrscfg.ChargerSConns { + cln.ChargerSConns[i] = con + } + } + if cdrscfg.RaterConns != nil { + cln.RaterConns = make([]string, len(cdrscfg.RaterConns)) + for i, con := range cdrscfg.RaterConns { + cln.RaterConns[i] = con + } + } + if cdrscfg.AttributeSConns != nil { + cln.AttributeSConns = make([]string, len(cdrscfg.AttributeSConns)) + for i, con := range cdrscfg.AttributeSConns { + cln.AttributeSConns[i] = con + } + } + if cdrscfg.ThresholdSConns != nil { + cln.ThresholdSConns = make([]string, len(cdrscfg.ThresholdSConns)) + for i, con := range cdrscfg.ThresholdSConns { + cln.ThresholdSConns[i] = con + } + } + if cdrscfg.StatSConns != nil { + cln.StatSConns = make([]string, len(cdrscfg.StatSConns)) + for i, con := range cdrscfg.StatSConns { + cln.StatSConns[i] = con + } + } + if cdrscfg.OnlineCDRExports != nil { + cln.OnlineCDRExports = make([]string, len(cdrscfg.OnlineCDRExports)) + for i, con := range cdrscfg.OnlineCDRExports { + cln.OnlineCDRExports[i] = con + } + } + if cdrscfg.SchedulerConns != nil { + cln.SchedulerConns = make([]string, len(cdrscfg.SchedulerConns)) + for i, con := range cdrscfg.SchedulerConns { + cln.SchedulerConns[i] = con + } + } + if cdrscfg.EEsConns != nil { + cln.EEsConns = make([]string, len(cdrscfg.EEsConns)) + for i, con := range cdrscfg.EEsConns { + cln.EEsConns[i] = con + } + } + + return +} diff --git a/config/cdrscfg_test.go b/config/cdrscfg_test.go index 7d73e02f6..7ebab2caf 100644 --- a/config/cdrscfg_test.go +++ b/config/cdrscfg_test.go @@ -54,7 +54,7 @@ func TestCdrsCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.cdrsCfg.loadFromJsonCfg(jsonCfg); err != nil { + } else if err = jsnCfg.cdrsCfg.loadFromJSONCfg(jsonCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.cdrsCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.cdrsCfg)) @@ -68,7 +68,7 @@ func TestExtraFieldsinloadFromJsonCfg(t *testing.T) { expectedErrMessage := "emtpy RSRParser in rule: <>" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.cdrsCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expectedErrMessage { + } else if err = jsonCfg.cdrsCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expectedErrMessage { t.Errorf("Expected %+v, received %+v", expectedErrMessage, err) } } @@ -140,3 +140,49 @@ func TestCdrsCfgAsMapInterface2(t *testing.T) { t.Errorf("Expected %+v \n, recieved %+v", eMap, rcv) } } + +func TestCdrsCfgClone(t *testing.T) { + ban := &CdrsCfg{ + Enabled: true, + StoreCdrs: true, + SMCostRetries: 1, + ChargerSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers), "*conn1"}, + RaterConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder), "*conn1"}, + AttributeSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes), "*conn1"}, + ThresholdSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"}, + StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "*conn1"}, + SchedulerConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler), "*conn1"}, + EEsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs), "*conn1"}, + OnlineCDRExports: []string{"randomVal"}, + ExtraFields: RSRParsers{}, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.ChargerSConns[1] = ""; ban.ChargerSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RaterConns[1] = ""; ban.RaterConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.AttributeSConns[1] = ""; ban.AttributeSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ThresholdSConns[1] = ""; ban.ThresholdSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.StatSConns[1] = ""; ban.StatSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.SchedulerConns[1] = ""; ban.SchedulerConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.EEsConns[1] = ""; ban.EEsConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + + if rcv.OnlineCDRExports[0] = ""; ban.OnlineCDRExports[0] != "randomVal" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/config.go b/config/config.go index 7b7595a63..764214439 100644 --- a/config/config.go +++ b/config/config.go @@ -147,7 +147,7 @@ func NewDefaultCGRConfig() (cfg *CGRConfig, err error) { cfg.storDbCfg = new(StorDbCfg) cfg.storDbCfg.Items = make(map[string]*ItemOpt) cfg.storDbCfg.Opts = make(map[string]interface{}) - cfg.tlsCfg = new(TlsCfg) + cfg.tlsCfg = new(TLSCfg) cfg.cacheCfg = new(CacheCfg) cfg.cacheCfg.Partitions = make(map[string]*CacheParamCfg) cfg.listenCfg = new(ListenCfg) @@ -282,18 +282,18 @@ type CGRConfig struct { dfltEvExp *EventExporterCfg // default event exporter loaderCfg LoaderSCfgs // LoaderS configs - httpAgentCfg HttpAgentCfgs // HttpAgent configs + httpAgentCfg HTTPAgentCfgs // HttpAgent configs rldChans map[string]chan struct{} // index here the channels used for reloads - rpcConns RpcConns + rpcConns RPCConns templates FcTemplates generalCfg *GeneralCfg // General config dataDbCfg *DataDbCfg // Database config storDbCfg *StorDbCfg // StroreDb config - tlsCfg *TlsCfg // TLS config + tlsCfg *TLSCfg // TLS config cacheCfg *CacheCfg // Cache config listenCfg *ListenCfg // Listen config httpCfg *HTTPCfg // HTTP config @@ -420,7 +420,7 @@ func (cfg *CGRConfig) loadRPCConns(jsnCfg *CgrJsonCfg) (err error) { } for key, val := range jsnRPCConns { cfg.rpcConns[key] = NewDfltRPCConn() - cfg.rpcConns[key].loadFromJsonCfg(val) + cfg.rpcConns[key].loadFromJSONCfg(val) } return } @@ -431,7 +431,7 @@ func (cfg *CGRConfig) loadGeneralCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnGeneralCfg, err = jsnCfg.GeneralJsonCfg(); err != nil { return } - return cfg.generalCfg.loadFromJsonCfg(jsnGeneralCfg) + return cfg.generalCfg.loadFromJSONCfg(jsnGeneralCfg) } // loadCacheCfg loads the Cache section of the configuration @@ -449,7 +449,7 @@ func (cfg *CGRConfig) loadListenCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnListenCfg, err = jsnCfg.ListenJsonCfg(); err != nil { return } - return cfg.listenCfg.loadFromJsonCfg(jsnListenCfg) + return cfg.listenCfg.loadFromJSONCfg(jsnListenCfg) } // loadHTTPCfg loads the Http section of the configuration @@ -458,7 +458,7 @@ func (cfg *CGRConfig) loadHTTPCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnHTTPCfg, err = jsnCfg.HttpJsonCfg(); err != nil { return } - return cfg.httpCfg.loadFromJsonCfg(jsnHTTPCfg) + return cfg.httpCfg.loadFromJSONCfg(jsnHTTPCfg) } // loadDataDBCfg loads the DataDB section of the configuration @@ -467,7 +467,7 @@ func (cfg *CGRConfig) loadDataDBCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnDataDbCfg, err = jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { return } - if err = cfg.dataDbCfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + if err = cfg.dataDbCfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { return } return @@ -480,7 +480,7 @@ func (cfg *CGRConfig) loadStorDBCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnDataDbCfg, err = jsnCfg.DbJsonCfg(STORDB_JSN); err != nil { return } - return cfg.storDbCfg.loadFromJsonCfg(jsnDataDbCfg) + return cfg.storDbCfg.loadFromJSONCfg(jsnDataDbCfg) } // loadFilterSCfg loads the FilterS section of the configuration @@ -489,7 +489,7 @@ func (cfg *CGRConfig) loadFilterSCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnFilterSCfg, err = jsnCfg.FilterSJsonCfg(); err != nil { return } - return cfg.filterSCfg.loadFromJsonCfg(jsnFilterSCfg) + return cfg.filterSCfg.loadFromJSONCfg(jsnFilterSCfg) } // loadRalSCfg loads the RalS section of the configuration @@ -498,7 +498,7 @@ func (cfg *CGRConfig) loadRalSCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnRALsCfg, err = jsnCfg.RalsJsonCfg(); err != nil { return } - return cfg.ralsCfg.loadFromJsonCfg(jsnRALsCfg) + return cfg.ralsCfg.loadFromJSONCfg(jsnRALsCfg) } // loadSchedulerCfg loads the Scheduler section of the configuration @@ -516,7 +516,7 @@ func (cfg *CGRConfig) loadCdrsCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnCdrsCfg, err = jsnCfg.CdrsJsonCfg(); err != nil { return } - return cfg.cdrsCfg.loadFromJsonCfg(jsnCdrsCfg) + return cfg.cdrsCfg.loadFromJSONCfg(jsnCdrsCfg) } // loadSessionSCfg loads the SessionS section of the configuration @@ -525,7 +525,7 @@ func (cfg *CGRConfig) loadSessionSCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnSessionSCfg, err = jsnCfg.SessionSJsonCfg(); err != nil { return } - return cfg.sessionSCfg.loadFromJsonCfg(jsnSessionSCfg) + return cfg.sessionSCfg.loadFromJSONCfg(jsnSessionSCfg) } // loadFreeswitchAgentCfg loads the FreeswitchAgent section of the configuration @@ -534,7 +534,7 @@ func (cfg *CGRConfig) loadFreeswitchAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnSmFsCfg, err = jsnCfg.FreeswitchAgentJsonCfg(); err != nil { return } - return cfg.fsAgentCfg.loadFromJsonCfg(jsnSmFsCfg) + return cfg.fsAgentCfg.loadFromJSONCfg(jsnSmFsCfg) } // loadKamAgentCfg loads the KamAgent section of the configuration @@ -543,7 +543,7 @@ func (cfg *CGRConfig) loadKamAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnKamAgentCfg, err = jsnCfg.KamAgentJsonCfg(); err != nil { return } - return cfg.kamAgentCfg.loadFromJsonCfg(jsnKamAgentCfg) + return cfg.kamAgentCfg.loadFromJSONCfg(jsnKamAgentCfg) } // loadAsteriskAgentCfg loads the AsteriskAgent section of the configuration @@ -552,7 +552,7 @@ func (cfg *CGRConfig) loadAsteriskAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnSMAstCfg, err = jsnCfg.AsteriskAgentJsonCfg(); err != nil { return } - return cfg.asteriskAgentCfg.loadFromJsonCfg(jsnSMAstCfg) + return cfg.asteriskAgentCfg.loadFromJSONCfg(jsnSMAstCfg) } // loadDiameterAgentCfg loads the DiameterAgent section of the configuration @@ -561,7 +561,7 @@ func (cfg *CGRConfig) loadDiameterAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnDACfg, err = jsnCfg.DiameterAgentJsonCfg(); err != nil { return } - return cfg.diameterAgentCfg.loadFromJsonCfg(jsnDACfg, cfg.generalCfg.RSRSep) + return cfg.diameterAgentCfg.loadFromJSONCfg(jsnDACfg, cfg.generalCfg.RSRSep) } // loadRadiusAgentCfg loads the RadiusAgent section of the configuration @@ -570,7 +570,7 @@ func (cfg *CGRConfig) loadRadiusAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnRACfg, err = jsnCfg.RadiusAgentJsonCfg(); err != nil { return } - return cfg.radiusAgentCfg.loadFromJsonCfg(jsnRACfg, cfg.generalCfg.RSRSep) + return cfg.radiusAgentCfg.loadFromJSONCfg(jsnRACfg, cfg.generalCfg.RSRSep) } // loadDNSAgentCfg loads the DNSAgent section of the configuration @@ -588,7 +588,7 @@ func (cfg *CGRConfig) loadHTTPAgentCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnHTTPAgntCfg, err = jsnCfg.HttpAgentJsonCfg(); err != nil { return } - return cfg.httpAgentCfg.loadFromJsonCfg(jsnHTTPAgntCfg, cfg.generalCfg.RSRSep) + return cfg.httpAgentCfg.loadFromJSONCfg(jsnHTTPAgntCfg, cfg.generalCfg.RSRSep) } // loadAttributeSCfg loads the AttributeS section of the configuration @@ -655,7 +655,7 @@ func (cfg *CGRConfig) loadLoaderSCfg(jsnCfg *CgrJsonCfg) (err error) { // cfg.loaderCfg = make(LoaderSCfgs, len(jsnLoaderCfg)) for _, profile := range jsnLoaderCfg { loadSCfgp := NewDfltLoaderSCfg() - if err = loadSCfgp.loadFromJsonCfg(profile, cfg.templates, cfg.generalCfg.RSRSep); err != nil { + if err = loadSCfgp.loadFromJSONCfg(profile, cfg.templates, cfg.generalCfg.RSRSep); err != nil { return } cfg.loaderCfg = append(cfg.loaderCfg, loadSCfgp) // use apend so the loaderS profile to be loaded from multiple files @@ -724,7 +724,7 @@ func (cfg *CGRConfig) loadTLSCgrCfg(jsnCfg *CgrJsonCfg) (err error) { if jsnTLSCgrCfg, err = jsnCfg.TlsCfgJson(); err != nil { return } - return cfg.tlsCfg.loadFromJsonCfg(jsnTLSCgrCfg) + return cfg.tlsCfg.loadFromJSONCfg(jsnTLSCgrCfg) } // loadAnalyzerCgrCfg loads the Analyzer section of the configuration @@ -922,7 +922,7 @@ func (cfg *CGRConfig) AsteriskAgentCfg() *AsteriskAgentCfg { } // HTTPAgentCfg returns the config for HttpAgent -func (cfg *CGRConfig) HTTPAgentCfg() HttpAgentCfgs { +func (cfg *CGRConfig) HTTPAgentCfg() HTTPAgentCfgs { cfg.lks[HttpAgentJson].Lock() defer cfg.lks[HttpAgentJson].Unlock() return cfg.httpAgentCfg @@ -1006,7 +1006,7 @@ func (cfg *CGRConfig) GeneralCfg() *GeneralCfg { } // TLSCfg returns the config for Tls -func (cfg *CGRConfig) TLSCfg() *TlsCfg { +func (cfg *CGRConfig) TLSCfg() *TLSCfg { cfg.lks[TlsCfgJson].Lock() defer cfg.lks[TlsCfgJson].Unlock() return cfg.tlsCfg @@ -1095,7 +1095,7 @@ func (cfg *CGRConfig) SIPAgentCfg() *SIPAgentCfg { } // RPCConns reads the RPCConns configuration -func (cfg *CGRConfig) RPCConns() RpcConns { +func (cfg *CGRConfig) RPCConns() RPCConns { cfg.lks[RPCConnsJsonName].RLock() defer cfg.lks[RPCConnsJsonName].RUnlock() return cfg.rpcConns @@ -1249,7 +1249,7 @@ func (cfg *CGRConfig) loadCfgWithLocks(path, section string) (err error) { func (*CGRConfig) loadConfigFromReader(rdr io.Reader, loadFuncs []func(jsnCfg *CgrJsonCfg) error, envOff bool) (err error) { jsnCfg := new(CgrJsonCfg) - var rjr *rjReader + var rjr *RjReader if rjr, err = NewRjReader(rdr); err != nil { return } @@ -1856,3 +1856,59 @@ func (cfg *CGRConfig) V1SetConfigFromJSON(args *SetConfigFromJSONArgs, reply *st *reply = utils.OK return } + +// Clone returns a deep copy of CGRConfig +func (cfg CGRConfig) Clone() (cln *CGRConfig) { + cln = &CGRConfig{ + DataFolderPath: cfg.DataFolderPath, + ConfigPath: cfg.ConfigPath, + + dfltEvRdr: cfg.dfltEvRdr.Clone(), + dfltEvExp: cfg.dfltEvExp.Clone(), + loaderCfg: cfg.loaderCfg.Clone(), + httpAgentCfg: cfg.httpAgentCfg.Clone(), + rpcConns: cfg.rpcConns.Clone(), + templates: cfg.templates.Clone(), + generalCfg: cfg.generalCfg.Clone(), + dataDbCfg: cfg.dataDbCfg.Clone(), + storDbCfg: cfg.storDbCfg.Clone(), + tlsCfg: cfg.tlsCfg.Clone(), + cacheCfg: cfg.cacheCfg.Clone(), + listenCfg: cfg.listenCfg.Clone(), + httpCfg: cfg.httpCfg.Clone(), + filterSCfg: cfg.filterSCfg.Clone(), + ralsCfg: cfg.ralsCfg.Clone(), + schedulerCfg: cfg.schedulerCfg.Clone(), + cdrsCfg: cfg.cdrsCfg.Clone(), + sessionSCfg: cfg.sessionSCfg.Clone(), + fsAgentCfg: cfg.fsAgentCfg.Clone(), + kamAgentCfg: cfg.kamAgentCfg.Clone(), + asteriskAgentCfg: cfg.asteriskAgentCfg.Clone(), + diameterAgentCfg: cfg.diameterAgentCfg.Clone(), + radiusAgentCfg: cfg.radiusAgentCfg.Clone(), + dnsAgentCfg: cfg.dnsAgentCfg.Clone(), + attributeSCfg: cfg.attributeSCfg.Clone(), + chargerSCfg: cfg.chargerSCfg.Clone(), + resourceSCfg: cfg.resourceSCfg.Clone(), + statsCfg: cfg.statsCfg.Clone(), + thresholdSCfg: cfg.thresholdSCfg.Clone(), + routeSCfg: cfg.routeSCfg.Clone(), + sureTaxCfg: cfg.sureTaxCfg.Clone(), + dispatcherSCfg: cfg.dispatcherSCfg.Clone(), + dispatcherHCfg: cfg.dispatcherHCfg.Clone(), + loaderCgrCfg: cfg.loaderCgrCfg.Clone(), + migratorCgrCfg: cfg.migratorCgrCfg.Clone(), + mailerCfg: cfg.mailerCfg.Clone(), + analyzerSCfg: cfg.analyzerSCfg.Clone(), + apier: cfg.apier.Clone(), + ersCfg: cfg.ersCfg.Clone(), + eesCfg: cfg.eesCfg.Clone(), + rateSCfg: cfg.rateSCfg.Clone(), + sipAgentCfg: cfg.sipAgentCfg.Clone(), + configSCfg: cfg.configSCfg.Clone(), + apiBanCfg: cfg.apiBanCfg.Clone(), + coreSCfg: cfg.coreSCfg.Clone(), + } + cln.initChanels() + return +} diff --git a/config/config_it_test.go b/config/config_it_test.go index 47047b321..3aa96dfa5 100644 --- a/config/config_it_test.go +++ b/config/config_it_test.go @@ -471,7 +471,7 @@ func testCGRConfigReloadSessionS(t *testing.T) { CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}, ReplicationConns: []string{}, - SessionIndexes: utils.NewStringMap(), + SessionIndexes: utils.StringSet{}, ClientProtocol: 1, TerminateAttempts: 5, AlterableFields: utils.NewStringSet([]string{}), @@ -845,7 +845,7 @@ func testCGRConfigReloadConfigFromJSONSessionS(t *testing.T) { CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}, ReplicationConns: []string{}, - SessionIndexes: utils.NewStringMap(), + SessionIndexes: utils.StringSet{}, ClientProtocol: 1, TerminateAttempts: 5, AlterableFields: utils.NewStringSet([]string{}), @@ -897,7 +897,7 @@ func testCGRConfigReloadConfigFromStringSessionS(t *testing.T) { CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}, ReplicationConns: []string{}, - SessionIndexes: utils.NewStringMap(), + SessionIndexes: utils.StringSet{}, ClientProtocol: 1, TerminateAttempts: 5, AlterableFields: utils.NewStringSet([]string{}), @@ -951,7 +951,7 @@ func testCGRConfigReloadAll(t *testing.T) { CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}, ReplicationConns: []string{}, - SessionIndexes: utils.NewStringMap(), + SessionIndexes: utils.StringSet{}, ClientProtocol: 1, TerminateAttempts: 5, AlterableFields: utils.NewStringSet([]string{}), diff --git a/config/config_test.go b/config/config_test.go index 143eecbdc..737da9aec 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -205,10 +205,10 @@ func TestHttpAgentCfg(t *testing.T) { } ` eCgrCfg, _ := NewDefaultCGRConfig() - eCgrCfg.httpAgentCfg = []*HttpAgentCfg{ + eCgrCfg.httpAgentCfg = []*HTTPAgentCfg{ { ID: "conecto1", - Url: "/conecto", + URL: "/conecto", RequestPayload: utils.MetaUrl, ReplyPayload: utils.MetaXml, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, @@ -480,7 +480,7 @@ func TestCgrCfgJSONDefaultsSMGenericCfg(t *testing.T) { DebitInterval: 0, StoreSCosts: false, SessionTTL: 0, - SessionIndexes: utils.StringMap{}, + SessionIndexes: utils.StringSet{}, ClientProtocol: 1.0, ChannelSyncInterval: 0, TerminateAttempts: 5, @@ -810,7 +810,7 @@ func TestCgrCfgJSONDefaultsDiameterAgentCfg(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, OriginHost: "CGR-DA", OriginRealm: "cgrates.org", - VendorId: 0, + VendorID: 0, ProductName: "CGRateS", ConcurrentReqs: -1, RequestProcessors: nil, @@ -834,8 +834,8 @@ func TestCgrCfgJSONDefaultsDiameterAgentCfg(t *testing.T) { if !reflect.DeepEqual(cgrCfg.diameterAgentCfg.OriginRealm, testDA.OriginRealm) { t.Errorf("received: %+v, expecting: %+v", cgrCfg.diameterAgentCfg.OriginRealm, testDA.OriginRealm) } - if !reflect.DeepEqual(cgrCfg.diameterAgentCfg.VendorId, testDA.VendorId) { - t.Errorf("received: %+v, expecting: %+v", cgrCfg.diameterAgentCfg.VendorId, testDA.VendorId) + if !reflect.DeepEqual(cgrCfg.diameterAgentCfg.VendorID, testDA.VendorID) { + t.Errorf("received: %+v, expecting: %+v", cgrCfg.diameterAgentCfg.VendorID, testDA.VendorID) } if !reflect.DeepEqual(cgrCfg.diameterAgentCfg.ProductName, testDA.ProductName) { t.Errorf("received: %+v, expecting: %+v", cgrCfg.diameterAgentCfg.ProductName, testDA.ProductName) @@ -1941,7 +1941,7 @@ func TestDiameterAgentConfig(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, OriginHost: "CGR-DA", OriginRealm: "cgrates.org", - VendorId: 0, + VendorID: 0, ProductName: "CGRateS", ConcurrentReqs: -1, SyncedConnReqs: false, @@ -2141,7 +2141,7 @@ func TestSessionSConfig(t *testing.T) { DebitInterval: 0, StoreSCosts: false, SessionTTL: 0, - SessionIndexes: utils.StringMap{}, + SessionIndexes: utils.StringSet{}, ClientProtocol: 1.0, ChannelSyncInterval: 0, TerminateAttempts: 5, @@ -2261,7 +2261,7 @@ func TestLoaderConfig(t *testing.T) { expected := LoaderSCfgs{ { Enabled: false, - Id: utils.MetaDefault, + ID: utils.MetaDefault, Tenant: ten, LockFileName: ".cgr.lck", CacheSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)}, @@ -2476,7 +2476,7 @@ func TestSIPAgentConfig(t *testing.T) { } func TestRPCConnsConfig(t *testing.T) { - expected := RpcConns{ + expected := RPCConns{ utils.MetaInternal: { Strategy: utils.MetaFirst, PoolSize: 0, @@ -2633,7 +2633,7 @@ func TestRLockAndRUnlock(t *testing.T) { func TestCgrLoaderCfgITDefaults(t *testing.T) { eCfg := LoaderSCfgs{ { - Id: utils.MetaDefault, + ID: utils.MetaDefault, Enabled: false, DryRun: false, RunDelay: 0, @@ -3457,7 +3457,7 @@ func TestCfgTlsCfg(t *testing.T) { }, }` eCgrCfg, _ := NewDefaultCGRConfig() - eCgrCfg.tlsCfg = &TlsCfg{ + eCgrCfg.tlsCfg = &TLSCfg{ ServerCerificate: "path/To/Server/Cert", ServerKey: "path/To/Server/Key", CaCertificate: "path/To/CA/Cert", @@ -3907,7 +3907,7 @@ func TestV1GetConfigRals(t *testing.T) { "*mms": "10000", }, utils.MaxIncrementsCfg: 1000000, - utils.BalanceRatingSubjectCfg: map[string]interface{}{ + utils.BalanceRatingSubjectCfg: map[string]string{ "*any": "*zero1ns", "*voice": "*zero1s", }, @@ -4136,10 +4136,10 @@ func TestV1GetConfigRadiusAgent(t *testing.T) { utils.ListenNetCfg: "udp", utils.ListenAuthCfg: "127.0.0.1:1812", utils.ListenAcctCfg: "127.0.0.1:1813", - utils.ClientSecretsCfg: map[string]interface{}{ + utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, - utils.ClientDictionariesCfg: map[string]interface{}{ + utils.ClientDictionariesCfg: map[string]string{ utils.MetaDefault: "/usr/share/cgrates/radius/dict/", }, utils.SessionSConnsCfg: []string{"*internal"}, @@ -5208,7 +5208,7 @@ func TestV1GetConfigAsJSONDispatcherH(t *testing.T) { func TestV1GetConfigAsJSONLoaders(t *testing.T) { var reply string - expected := `{"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.4"}],"file_name":"DispatcherHosts.csv","type":"*dispatcher_hosts"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.4"},{"path":"ConnectFee","tag":"ConnectFee","type":"*variable","value":"~*req.5"},{"path":"RoundingMethod","tag":"RoundingMethod","type":"*variable","value":"~*req.6"},{"path":"RoundingDecimals","tag":"RoundingDecimals","type":"*variable","value":"~*req.7"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.8"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.9"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.10"},{"path":"RateID","tag":"RateID","type":"*variable","value":"~*req.11"},{"path":"RateFilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.12"},{"path":"RateActivationStart","tag":"RateActivationStart","type":"*variable","value":"~*req.13"},{"path":"RateWeight","tag":"RateWeight","type":"*variable","value":"~*req.14"},{"path":"RateBlocker","tag":"RateBlocker","type":"*variable","value":"~*req.15"},{"path":"RateIntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.16"},{"path":"RateValue","tag":"RateValue","type":"*variable","value":"~*req.17"},{"path":"RateUnit","tag":"RateUnit","type":"*variable","value":"~*req.18"},{"path":"RateIncrement","tag":"RateIncrement","type":"*variable","value":"~*req.19"}],"file_name":"RateProfiles.csv","type":"*rate_profiles"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}]}` + expected := `{"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.4"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.4"},{"path":"ConnectFee","tag":"ConnectFee","type":"*variable","value":"~*req.5"},{"path":"RoundingMethod","tag":"RoundingMethod","type":"*variable","value":"~*req.6"},{"path":"RoundingDecimals","tag":"RoundingDecimals","type":"*variable","value":"~*req.7"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.8"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.9"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.10"},{"path":"RateID","tag":"RateID","type":"*variable","value":"~*req.11"},{"path":"RateFilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.12"},{"path":"RateActivationStart","tag":"RateActivationStart","type":"*variable","value":"~*req.13"},{"path":"RateWeight","tag":"RateWeight","type":"*variable","value":"~*req.14"},{"path":"RateBlocker","tag":"RateBlocker","type":"*variable","value":"~*req.15"},{"path":"RateIntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.16"},{"path":"RateValue","tag":"RateValue","type":"*variable","value":"~*req.17"},{"path":"RateUnit","tag":"RateUnit","type":"*variable","value":"~*req.18"},{"path":"RateIncrement","tag":"RateIncrement","type":"*variable","value":"~*req.19"}],"file_name":"RateProfiles.csv","flags":null,"type":"*rate_profiles"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}]}` if cgrCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) } else if err := cgrCfg.V1GetConfigAsJSON(&SectionWithOpts{Section: LoaderJson}, &reply); err != nil { @@ -5445,7 +5445,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) { } }` var reply string - expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*internal"]},"attributes":{"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"process_runs":1,"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*accounts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*cdrs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*event_charges":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*session_costs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_account_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_attributes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_chargers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destination_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rate_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_stats":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*versions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""}},"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"remote":false,"replicate":false},"*accounts":{"remote":false,"replicate":false},"*action_plans":{"remote":false,"replicate":false},"*action_triggers":{"remote":false,"replicate":false},"*actions":{"remote":false,"replicate":false},"*attribute_profiles":{"remote":false,"replicate":false},"*charger_profiles":{"remote":false,"replicate":false},"*destinations":{"remote":false,"replicate":false},"*dispatcher_hosts":{"remote":false,"replicate":false},"*dispatcher_profiles":{"remote":false,"replicate":false},"*filters":{"remote":false,"replicate":false},"*indexes":{"remote":false,"replicate":false},"*load_ids":{"remote":false,"replicate":false},"*rate_profiles":{"remote":false,"replicate":false},"*rating_plans":{"remote":false,"replicate":false},"*rating_profiles":{"remote":false,"replicate":false},"*resource_profiles":{"remote":false,"replicate":false},"*resources":{"remote":false,"replicate":false},"*reverse_destinations":{"remote":false,"replicate":false},"*route_profiles":{"remote":false,"replicate":false},"*shared_groups":{"remote":false,"replicate":false},"*statqueue_profiles":{"remote":false,"replicate":false},"*statqueues":{"remote":false,"replicate":false},"*threshold_profiles":{"remote":false,"replicate":false},"*thresholds":{"remote":false,"replicate":false},"*timings":{"remote":false,"replicate":false}},"opts":{"query_timeout":"10s","redis_ca_certificate":"","redis_client_certificate":"","redis_client_key":"","redis_cluster":false,"redis_cluster_ondown_delay":"0","redis_cluster_sync":"5s","redis_sentinel":"","redis_tls":false},"remote_conns":[],"replication_conns":[]},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*internal"],"synced_conn_requests":false,"vendor_id":0},"dispatcherh":{"dispatchers_conns":[],"enabled":false,"hosts":{},"register_interval":"5m0s"},"dispatchers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"export_path":"/var/spool/cgrates/ees","field_separator":",","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"tenant":"","timezone":"","type":"*none"}]},"ers":{"enabled":false,"readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"failed_calls_prefix":"","field_separator":",","fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"header_define_character":":","id":"*default","opts":{},"partial_cache_expiry_action":"","partial_record_cache":"0","processed_path":"/var/spool/cgrates/ers/out","row_length":0,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none","xml_root_path":[""]}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_call_duration":"3h0m0s","max_parallel_conns":100,"min_call_duration":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"dispatchers_registrar_url":"/dispatchers_registrar","freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","reconnects":5}],"sessions_conns":["*internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.4"}],"file_name":"DispatcherHosts.csv","type":"*dispatcher_hosts"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.4"},{"path":"ConnectFee","tag":"ConnectFee","type":"*variable","value":"~*req.5"},{"path":"RoundingMethod","tag":"RoundingMethod","type":"*variable","value":"~*req.6"},{"path":"RoundingDecimals","tag":"RoundingDecimals","type":"*variable","value":"~*req.7"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.8"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.9"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.10"},{"path":"RateID","tag":"RateID","type":"*variable","value":"~*req.11"},{"path":"RateFilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.12"},{"path":"RateActivationStart","tag":"RateActivationStart","type":"*variable","value":"~*req.13"},{"path":"RateWeight","tag":"RateWeight","type":"*variable","value":"~*req.14"},{"path":"RateBlocker","tag":"RateBlocker","type":"*variable","value":"~*req.15"},{"path":"RateIntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.16"},{"path":"RateValue","tag":"RateValue","type":"*variable","value":"~*req.17"},{"path":"RateUnit","tag":"RateUnit","type":"*variable","value":"~*req.18"},{"path":"RateIncrement","tag":"RateIncrement","type":"*variable","value":"~*req.19"}],"file_name":"RateProfiles.csv","type":"*rate_profiles"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"redis_ca_certificate":"","redis_client_certificate":"","redis_client_key":"","redis_cluster":false,"redis_cluster_ondown_delay":"0","redis_cluster_sync":"5s","redis_sentinel":"","redis_tls":false},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"caches_conns":["*internal"],"dynaprepaid_actionplans":[],"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"rates":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rate_indexed_selects":true,"rate_nested_fields":false,"rate_prefix_indexed_fields":[],"rate_suffix_indexed_fields":[],"suffix_indexed_fields":[]},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rals_conns":[],"rates_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*internal":{"conns":[{"TLS":false,"address":"*internal","synchronous":false,"transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"TLS":false,"address":"127.0.0.1:2012","synchronous":false,"transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","enabled":false,"listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"remote":false,"replicate":false},"*session_costs":{"remote":false,"replicate":false},"*tp_account_actions":{"remote":false,"replicate":false},"*tp_action_plans":{"remote":false,"replicate":false},"*tp_action_triggers":{"remote":false,"replicate":false},"*tp_actions":{"remote":false,"replicate":false},"*tp_attributes":{"remote":false,"replicate":false},"*tp_chargers":{"remote":false,"replicate":false},"*tp_destination_rates":{"remote":false,"replicate":false},"*tp_destinations":{"remote":false,"replicate":false},"*tp_dispatcher_hosts":{"remote":false,"replicate":false},"*tp_dispatcher_profiles":{"remote":false,"replicate":false},"*tp_filters":{"remote":false,"replicate":false},"*tp_rate_profiles":{"remote":false,"replicate":false},"*tp_rates":{"remote":false,"replicate":false},"*tp_rating_plans":{"remote":false,"replicate":false},"*tp_rating_profiles":{"remote":false,"replicate":false},"*tp_resources":{"remote":false,"replicate":false},"*tp_routes":{"remote":false,"replicate":false},"*tp_shared_groups":{"remote":false,"replicate":false},"*tp_stats":{"remote":false,"replicate":false},"*tp_thresholds":{"remote":false,"replicate":false},"*tp_timings":{"remote":false,"replicate":false},"*versions":{"remote":false,"replicate":false}},"opts":{"conn_max_lifetime":0,"max_idle_conns":10,"max_open_conns":100,"query_timeout":"10s","sslmode":"disable"},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` + expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*internal"]},"attributes":{"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"process_runs":1,"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*accounts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*cdrs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*event_charges":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rate_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*session_costs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_account_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_attributes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_chargers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destination_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rate_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_stats":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*versions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""}},"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"remote":false,"replicate":false},"*accounts":{"remote":false,"replicate":false},"*action_plans":{"remote":false,"replicate":false},"*action_triggers":{"remote":false,"replicate":false},"*actions":{"remote":false,"replicate":false},"*attribute_profiles":{"remote":false,"replicate":false},"*charger_profiles":{"remote":false,"replicate":false},"*destinations":{"remote":false,"replicate":false},"*dispatcher_hosts":{"remote":false,"replicate":false},"*dispatcher_profiles":{"remote":false,"replicate":false},"*filters":{"remote":false,"replicate":false},"*indexes":{"remote":false,"replicate":false},"*load_ids":{"remote":false,"replicate":false},"*rate_profiles":{"remote":false,"replicate":false},"*rating_plans":{"remote":false,"replicate":false},"*rating_profiles":{"remote":false,"replicate":false},"*resource_profiles":{"remote":false,"replicate":false},"*resources":{"remote":false,"replicate":false},"*reverse_destinations":{"remote":false,"replicate":false},"*route_profiles":{"remote":false,"replicate":false},"*shared_groups":{"remote":false,"replicate":false},"*statqueue_profiles":{"remote":false,"replicate":false},"*statqueues":{"remote":false,"replicate":false},"*threshold_profiles":{"remote":false,"replicate":false},"*thresholds":{"remote":false,"replicate":false},"*timings":{"remote":false,"replicate":false}},"opts":{"query_timeout":"10s","redis_ca_certificate":"","redis_client_certificate":"","redis_client_key":"","redis_cluster":false,"redis_cluster_ondown_delay":"0","redis_cluster_sync":"5s","redis_sentinel":"","redis_tls":false},"remote_conns":[],"replication_conns":[]},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*internal"],"synced_conn_requests":false,"vendor_id":0},"dispatcherh":{"dispatchers_conns":[],"enabled":false,"hosts":{},"register_interval":"5m0s"},"dispatchers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"export_path":"/var/spool/cgrates/ees","field_separator":",","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"tenant":"","timezone":"","type":"*none"}]},"ers":{"enabled":false,"readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"failed_calls_prefix":"","field_separator":",","fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"header_define_character":":","id":"*default","opts":{},"partial_cache_expiry_action":"","partial_record_cache":"0","processed_path":"/var/spool/cgrates/ers/out","row_length":0,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none","xml_root_path":[""]}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_call_duration":"3h0m0s","max_parallel_conns":100,"min_call_duration":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"dispatchers_registrar_url":"/dispatchers_registrar","freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","reconnects":5}],"sessions_conns":["*internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.4"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.4"},{"path":"ConnectFee","tag":"ConnectFee","type":"*variable","value":"~*req.5"},{"path":"RoundingMethod","tag":"RoundingMethod","type":"*variable","value":"~*req.6"},{"path":"RoundingDecimals","tag":"RoundingDecimals","type":"*variable","value":"~*req.7"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.8"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.9"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.10"},{"path":"RateID","tag":"RateID","type":"*variable","value":"~*req.11"},{"path":"RateFilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.12"},{"path":"RateActivationStart","tag":"RateActivationStart","type":"*variable","value":"~*req.13"},{"path":"RateWeight","tag":"RateWeight","type":"*variable","value":"~*req.14"},{"path":"RateBlocker","tag":"RateBlocker","type":"*variable","value":"~*req.15"},{"path":"RateIntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.16"},{"path":"RateValue","tag":"RateValue","type":"*variable","value":"~*req.17"},{"path":"RateUnit","tag":"RateUnit","type":"*variable","value":"~*req.18"},{"path":"RateIncrement","tag":"RateIncrement","type":"*variable","value":"~*req.19"}],"file_name":"RateProfiles.csv","flags":null,"type":"*rate_profiles"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"redis_ca_certificate":"","redis_client_certificate":"","redis_client_key":"","redis_cluster":false,"redis_cluster_ondown_delay":"0","redis_cluster_sync":"5s","redis_sentinel":"","redis_tls":false},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"caches_conns":["*internal"],"dynaprepaid_actionplans":[],"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"rates":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rate_indexed_selects":true,"rate_nested_fields":false,"rate_prefix_indexed_fields":[],"rate_suffix_indexed_fields":[],"suffix_indexed_fields":[]},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rals_conns":[],"rates_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*internal":{"conns":[{"TLS":false,"address":"*internal","synchronous":false,"transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"TLS":false,"address":"127.0.0.1:2012","synchronous":false,"transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","enabled":false,"listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"remote":false,"replicate":false},"*session_costs":{"remote":false,"replicate":false},"*tp_account_actions":{"remote":false,"replicate":false},"*tp_action_plans":{"remote":false,"replicate":false},"*tp_action_triggers":{"remote":false,"replicate":false},"*tp_actions":{"remote":false,"replicate":false},"*tp_attributes":{"remote":false,"replicate":false},"*tp_chargers":{"remote":false,"replicate":false},"*tp_destination_rates":{"remote":false,"replicate":false},"*tp_destinations":{"remote":false,"replicate":false},"*tp_dispatcher_hosts":{"remote":false,"replicate":false},"*tp_dispatcher_profiles":{"remote":false,"replicate":false},"*tp_filters":{"remote":false,"replicate":false},"*tp_rate_profiles":{"remote":false,"replicate":false},"*tp_rates":{"remote":false,"replicate":false},"*tp_rating_plans":{"remote":false,"replicate":false},"*tp_rating_profiles":{"remote":false,"replicate":false},"*tp_resources":{"remote":false,"replicate":false},"*tp_routes":{"remote":false,"replicate":false},"*tp_shared_groups":{"remote":false,"replicate":false},"*tp_stats":{"remote":false,"replicate":false},"*tp_thresholds":{"remote":false,"replicate":false},"*tp_timings":{"remote":false,"replicate":false},"*versions":{"remote":false,"replicate":false}},"opts":{"conn_max_lifetime":0,"max_idle_conns":10,"max_open_conns":100,"query_timeout":"10s","sslmode":"disable"},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON) if err != nil { t.Fatal(err) @@ -5646,7 +5646,8 @@ func TestCgrCfgEventExporterDefault(t *testing.T) { ExportPath: "/var/spool/cgrates/ees", Attempts: 1, Timezone: utils.EmptyString, - Filters: nil, + Filters: []string{}, + AttributeSIDs: []string{}, Flags: utils.FlagsWithParams{}, contentFields: []*FCTemplate{}, Fields: []*FCTemplate{}, @@ -5661,7 +5662,7 @@ func TestCgrCfgEventExporterDefault(t *testing.T) { } func TestRpcConnsDefaults(t *testing.T) { - eCfg := make(RpcConns) + eCfg := make(RPCConns) // hardoded the *internal and *localhost connections eCfg[utils.MetaInternal] = &RPCConn{ Strategy: rpcclient.PoolFirst, @@ -5823,3 +5824,151 @@ func TestLoadCfgFromJSONWithLocksInvalidSeciton(t *testing.T) { t.Errorf("Expected %+v, received %+v", expected, err) } } + +func TestCGRConfigClone(t *testing.T) { + cfg, _ := NewDefaultCGRConfig() + rcv := cfg.Clone() + cfg.rldChans = nil + rcv.rldChans = nil + cfg.lks = nil + rcv.lks = nil + if !reflect.DeepEqual(cfg, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg), utils.ToJSON(rcv)) + } + + if !reflect.DeepEqual(cfg.dfltEvRdr, rcv.dfltEvRdr) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dfltEvRdr), utils.ToJSON(rcv.dfltEvRdr)) + } + if !reflect.DeepEqual(cfg.dfltEvExp, rcv.dfltEvExp) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dfltEvExp), utils.ToJSON(rcv.dfltEvExp)) + } + if !reflect.DeepEqual(cfg.loaderCfg, rcv.loaderCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.loaderCfg), utils.ToJSON(rcv.loaderCfg)) + } + if !reflect.DeepEqual(cfg.httpAgentCfg, rcv.httpAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.httpAgentCfg), utils.ToJSON(rcv.httpAgentCfg)) + } + if !reflect.DeepEqual(cfg.rpcConns, rcv.rpcConns) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.rpcConns), utils.ToJSON(rcv.rpcConns)) + } + if !reflect.DeepEqual(cfg.templates, rcv.templates) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.templates), utils.ToJSON(rcv.templates)) + } + if !reflect.DeepEqual(cfg.generalCfg, rcv.generalCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.generalCfg), utils.ToJSON(rcv.generalCfg)) + } + if !reflect.DeepEqual(cfg.dataDbCfg, rcv.dataDbCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dataDbCfg), utils.ToJSON(rcv.dataDbCfg)) + } + if !reflect.DeepEqual(cfg.storDbCfg, rcv.storDbCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.storDbCfg), utils.ToJSON(rcv.storDbCfg)) + } + if !reflect.DeepEqual(cfg.tlsCfg, rcv.tlsCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.tlsCfg), utils.ToJSON(rcv.tlsCfg)) + } + if !reflect.DeepEqual(cfg.cacheCfg, rcv.cacheCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.cacheCfg), utils.ToJSON(rcv.cacheCfg)) + } + if !reflect.DeepEqual(cfg.listenCfg, rcv.listenCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.listenCfg), utils.ToJSON(rcv.listenCfg)) + } + if !reflect.DeepEqual(cfg.httpCfg, rcv.httpCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.httpCfg), utils.ToJSON(rcv.httpCfg)) + } + if !reflect.DeepEqual(cfg.filterSCfg, rcv.filterSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.filterSCfg), utils.ToJSON(rcv.filterSCfg)) + } + if !reflect.DeepEqual(cfg.ralsCfg, rcv.ralsCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.ralsCfg), utils.ToJSON(rcv.ralsCfg)) + } + if !reflect.DeepEqual(cfg.schedulerCfg, rcv.schedulerCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.schedulerCfg), utils.ToJSON(rcv.schedulerCfg)) + } + if !reflect.DeepEqual(cfg.cdrsCfg, rcv.cdrsCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.cdrsCfg), utils.ToJSON(rcv.cdrsCfg)) + } + if !reflect.DeepEqual(cfg.sessionSCfg, rcv.sessionSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.sessionSCfg), utils.ToJSON(rcv.sessionSCfg)) + } + if !reflect.DeepEqual(cfg.fsAgentCfg, rcv.fsAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.fsAgentCfg), utils.ToJSON(rcv.fsAgentCfg)) + } + if !reflect.DeepEqual(cfg.kamAgentCfg, rcv.kamAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.kamAgentCfg), utils.ToJSON(rcv.kamAgentCfg)) + } + if !reflect.DeepEqual(cfg.asteriskAgentCfg, rcv.asteriskAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.asteriskAgentCfg), utils.ToJSON(rcv.asteriskAgentCfg)) + } + if !reflect.DeepEqual(cfg.diameterAgentCfg, rcv.diameterAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.diameterAgentCfg), utils.ToJSON(rcv.diameterAgentCfg)) + } + if !reflect.DeepEqual(cfg.radiusAgentCfg, rcv.radiusAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.radiusAgentCfg), utils.ToJSON(rcv.radiusAgentCfg)) + } + if !reflect.DeepEqual(cfg.dnsAgentCfg, rcv.dnsAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dnsAgentCfg), utils.ToJSON(rcv.dnsAgentCfg)) + } + if !reflect.DeepEqual(cfg.attributeSCfg, rcv.attributeSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.attributeSCfg), utils.ToJSON(rcv.attributeSCfg)) + } + if !reflect.DeepEqual(cfg.chargerSCfg, rcv.chargerSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.chargerSCfg), utils.ToJSON(rcv.chargerSCfg)) + } + if !reflect.DeepEqual(cfg.resourceSCfg, rcv.resourceSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.resourceSCfg), utils.ToJSON(rcv.resourceSCfg)) + } + if !reflect.DeepEqual(cfg.statsCfg, rcv.statsCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.statsCfg), utils.ToJSON(rcv.statsCfg)) + } + if !reflect.DeepEqual(cfg.thresholdSCfg, rcv.thresholdSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.thresholdSCfg), utils.ToJSON(rcv.thresholdSCfg)) + } + if !reflect.DeepEqual(cfg.routeSCfg, rcv.routeSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.routeSCfg), utils.ToJSON(rcv.routeSCfg)) + } + if !reflect.DeepEqual(cfg.sureTaxCfg, rcv.sureTaxCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.sureTaxCfg), utils.ToJSON(rcv.sureTaxCfg)) + } + if !reflect.DeepEqual(cfg.dispatcherSCfg, rcv.dispatcherSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dispatcherSCfg), utils.ToJSON(rcv.dispatcherSCfg)) + } + if !reflect.DeepEqual(cfg.dispatcherHCfg, rcv.dispatcherHCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.dispatcherHCfg), utils.ToJSON(rcv.dispatcherHCfg)) + } + if !reflect.DeepEqual(cfg.loaderCgrCfg, rcv.loaderCgrCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.loaderCgrCfg), utils.ToJSON(rcv.loaderCgrCfg)) + } + if !reflect.DeepEqual(cfg.migratorCgrCfg, rcv.migratorCgrCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.migratorCgrCfg), utils.ToJSON(rcv.migratorCgrCfg)) + } + if !reflect.DeepEqual(cfg.mailerCfg, rcv.mailerCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.mailerCfg), utils.ToJSON(rcv.mailerCfg)) + } + if !reflect.DeepEqual(cfg.analyzerSCfg, rcv.analyzerSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.analyzerSCfg), utils.ToJSON(rcv.analyzerSCfg)) + } + if !reflect.DeepEqual(cfg.apier, rcv.apier) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.apier), utils.ToJSON(rcv.apier)) + } + if !reflect.DeepEqual(cfg.ersCfg, rcv.ersCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.ersCfg), utils.ToJSON(rcv.ersCfg)) + } + if !reflect.DeepEqual(cfg.eesCfg, rcv.eesCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.eesCfg), utils.ToJSON(rcv.eesCfg)) + } + if !reflect.DeepEqual(cfg.rateSCfg, rcv.rateSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.rateSCfg), utils.ToJSON(rcv.rateSCfg)) + } + if !reflect.DeepEqual(cfg.sipAgentCfg, rcv.sipAgentCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.sipAgentCfg), utils.ToJSON(rcv.sipAgentCfg)) + } + if !reflect.DeepEqual(cfg.configSCfg, rcv.configSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.configSCfg), utils.ToJSON(rcv.configSCfg)) + } + if !reflect.DeepEqual(cfg.apiBanCfg, rcv.apiBanCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.apiBanCfg), utils.ToJSON(rcv.apiBanCfg)) + } + if !reflect.DeepEqual(cfg.coreSCfg, rcv.coreSCfg) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(cfg.coreSCfg), utils.ToJSON(rcv.coreSCfg)) + } +} diff --git a/config/configsanity_test.go b/config/configsanity_test.go index 6ffaa0ac6..0c9a6510a 100644 --- a/config/configsanity_test.go +++ b/config/configsanity_test.go @@ -592,8 +592,8 @@ func TestConfigSanityHTTPAgent1(t *testing.T) { if err != nil { t.Error(err) } - cfg.httpAgentCfg = HttpAgentCfgs{ - &HttpAgentCfg{ + cfg.httpAgentCfg = HTTPAgentCfgs{ + &HTTPAgentCfg{ SessionSConns: []string{utils.MetaInternal}, RequestProcessors: []*RequestProcessor{ { @@ -1115,7 +1115,7 @@ func TestConfigSanityDispatcherH(t *testing.T) { t.Errorf("Expecting: %+q received: %+q", expected, err) } - cfg.rpcConns = RpcConns{ + cfg.rpcConns = RPCConns{ utils.MetaLocalHost: {}, "*conn1": {}, } diff --git a/config/datadbcfg.go b/config/datadbcfg.go index f20c245d2..9b94159f6 100644 --- a/config/datadbcfg.go +++ b/config/datadbcfg.go @@ -40,8 +40,8 @@ type DataDbCfg struct { Opts map[string]interface{} } -//loadFromJsonCfg loads Database config from JsonCfg -func (dbcfg *DataDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { +// loadFromJSONCfg loads Database config from JsonCfg +func (dbcfg *DataDbCfg) loadFromJSONCfg(jsnDbCfg *DbJsonCfg) (err error) { if jsnDbCfg == nil { return nil } @@ -93,7 +93,7 @@ func (dbcfg *DataDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { if val == nil || !has { val = new(ItemOpt) } - val.loadFromJsonCfg(vJsn) //To review if the function signature changes + val.loadFromJSONCfg(vJsn) //To review if the function signature changes dbcfg.Items[kJsn] = val } } @@ -106,29 +106,40 @@ func (dbcfg *DataDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { } // Clone returns the cloned object -func (dbcfg *DataDbCfg) Clone() *DataDbCfg { - itms := make(map[string]*ItemOpt) - for k, itm := range dbcfg.Items { - itms[k] = itm.Clone() - } - opts := make(map[string]interface{}) - for k, v := range dbcfg.Opts { - opts[k] = v - } - return &DataDbCfg{ +func (dbcfg *DataDbCfg) Clone() (cln *DataDbCfg) { + cln = &DataDbCfg{ DataDbType: dbcfg.DataDbType, DataDbHost: dbcfg.DataDbHost, DataDbPort: dbcfg.DataDbPort, DataDbName: dbcfg.DataDbName, DataDbUser: dbcfg.DataDbUser, DataDbPass: dbcfg.DataDbPass, - RplConns: dbcfg.RplConns, - RmtConns: dbcfg.RmtConns, - Items: itms, - Opts: opts, + Items: make(map[string]*ItemOpt), + Opts: make(map[string]interface{}), } + for k, itm := range dbcfg.Items { + cln.Items[k] = itm.Clone() + } + for k, v := range dbcfg.Opts { + cln.Opts[k] = v + } + + if dbcfg.RmtConns != nil { + cln.RmtConns = make([]string, len(dbcfg.RmtConns)) + for i, conn := range dbcfg.RmtConns { + cln.RmtConns[i] = conn + } + } + if dbcfg.RplConns != nil { + cln.RplConns = make([]string, len(dbcfg.RplConns)) + for i, conn := range dbcfg.RplConns { + cln.RplConns[i] = conn + } + } + return } +// AsMapInterface returns the config as a map[string]interface{} func (dbcfg *DataDbCfg) AsMapInterface() (initialMP map[string]interface{}, err error) { initialMP = map[string]interface{}{ utils.DataDbTypeCfg: utils.Meta + dbcfg.DataDbType, @@ -157,6 +168,7 @@ func (dbcfg *DataDbCfg) AsMapInterface() (initialMP map[string]interface{}, err return } +// ItemOpt the options for the stored items type ItemOpt struct { Remote bool Replicate bool @@ -165,6 +177,7 @@ type ItemOpt struct { APIKey string } +// AsMapInterface returns the config as a map[string]interface{} func (itm *ItemOpt) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.RemoteCfg: itm.Remote, @@ -179,7 +192,7 @@ func (itm *ItemOpt) AsMapInterface() (initialMP map[string]interface{}) { return } -func (itm *ItemOpt) loadFromJsonCfg(jsonItm *ItemOptJson) { +func (itm *ItemOpt) loadFromJSONCfg(jsonItm *ItemOptJson) { if jsonItm == nil { return } @@ -198,6 +211,7 @@ func (itm *ItemOpt) loadFromJsonCfg(jsonItm *ItemOptJson) { return } +// Clone returns a deep copy of ItemOpt func (itm *ItemOpt) Clone() *ItemOpt { return &ItemOpt{ Remote: itm.Remote, diff --git a/config/datadbcfg_test.go b/config/datadbcfg_test.go index a21208e31..9388b7e6c 100644 --- a/config/datadbcfg_test.go +++ b/config/datadbcfg_test.go @@ -77,9 +77,9 @@ func TestDataDbCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.dataDbCfg.loadFromJsonCfg(nil); err != nil { + } else if err = jsnCfg.dataDbCfg.loadFromJSONCfg(nil); err != nil { t.Error(err) - } else if err = jsnCfg.dataDbCfg.loadFromJsonCfg(jsonCfg); err != nil { + } else if err = jsnCfg.dataDbCfg.loadFromJSONCfg(jsonCfg); err != nil { t.Error(err) } else { if !reflect.DeepEqual(expected.Items[utils.MetaAccounts], jsnCfg.dataDbCfg.Items[utils.MetaAccounts]) { @@ -101,7 +101,7 @@ func TestConnsloadFromJsonCfg(t *testing.T) { expectedErrRmt := "Remote connection ID needs to be different than *internal" if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.dataDbCfg.loadFromJsonCfg(jsonCfg); err == nil || err.Error() != expectedErrRmt { + } else if err = jsnCfg.dataDbCfg.loadFromJSONCfg(jsonCfg); err == nil || err.Error() != expectedErrRmt { t.Errorf("Expected %+v, received %+v", expectedErrRmt, err) } @@ -111,7 +111,7 @@ func TestConnsloadFromJsonCfg(t *testing.T) { expectedErrRpl := "Replication connection ID needs to be different than *internal" if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.dataDbCfg.loadFromJsonCfg(jsonCfg); err == nil || err.Error() != expectedErrRpl { + } else if err = jsnCfg.dataDbCfg.loadFromJSONCfg(jsonCfg); err == nil || err.Error() != expectedErrRpl { t.Errorf("Expected %+v, received %+v", expectedErrRpl, err) } } @@ -130,8 +130,8 @@ func TestItemCfgloadFromJson(t *testing.T) { RouteID: "randomID", } rcv := new(ItemOpt) - rcv.loadFromJsonCfg(nil) - rcv.loadFromJsonCfg(jsonCfg) + rcv.loadFromJSONCfg(nil) + rcv.loadFromJSONCfg(jsonCfg) if !reflect.DeepEqual(rcv, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) } @@ -153,7 +153,7 @@ func TestDataDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -173,7 +173,7 @@ func TestDataDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -193,7 +193,7 @@ func TestDataDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -234,7 +234,7 @@ func TestDataDBRemoteReplication(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -265,7 +265,7 @@ func TestDataDBRemoteReplication(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -296,7 +296,7 @@ func TestDataDBRemoteReplication(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -354,7 +354,7 @@ func TestDataDbCfgloadFromJsonCfgItems(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -412,7 +412,7 @@ func TestDataDbCfgloadFromJsonCfgItems(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -462,7 +462,7 @@ func TestDataDbCfgloadFromJsonCfgItems(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v ,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(dbcfg)) @@ -572,7 +572,7 @@ func TestCloneDataDB(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.dataDbCfg.loadFromJsonCfg(jsonCfg); err != nil { + } else if err = jsnCfg.dataDbCfg.loadFromJSONCfg(jsonCfg); err != nil { t.Error(err) } else { rcv := jsnCfg.dataDbCfg.Clone() diff --git a/config/diametercfg.go b/config/diametercfg.go index c4f7a84d6..9f96661de 100644 --- a/config/diametercfg.go +++ b/config/diametercfg.go @@ -19,11 +19,10 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) +// DiameterAgentCfg the config section that describes the Diameter Agent type DiameterAgentCfg struct { Enabled bool // enables the diameter agent: ListenNet string // sctp or tcp @@ -32,7 +31,7 @@ type DiameterAgentCfg struct { SessionSConns []string OriginHost string OriginRealm string - VendorId int + VendorID int ProductName string ConcurrentReqs int // limit the maximum number of requests processed SyncedConnReqs bool @@ -42,7 +41,7 @@ type DiameterAgentCfg struct { RequestProcessors []*RequestProcessor } -func (da *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg, separator string) (err error) { +func (da *DiameterAgentCfg) loadFromJSONCfg(jsnCfg *DiameterAgentJsonCfg, separator string) (err error) { if jsnCfg == nil { return nil } @@ -62,10 +61,9 @@ func (da *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg, separa da.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, attrConn := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + da.SessionSConns[idx] = attrConn if attrConn == utils.MetaInternal { da.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - } else { - da.SessionSConns[idx] = attrConn } } } @@ -76,7 +74,7 @@ func (da *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg, separa da.OriginRealm = *jsnCfg.Origin_realm } if jsnCfg.Vendor_id != nil { - da.VendorId = *jsnCfg.Vendor_id + da.VendorID = *jsnCfg.Vendor_id } if jsnCfg.Product_name != nil { da.ProductName = *jsnCfg.Product_name @@ -118,40 +116,71 @@ func (da *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg, separa return } -func (ds *DiameterAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { +// AsMapInterface returns the config as a map[string]interface{} +func (da *DiameterAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.EnabledCfg: ds.Enabled, - utils.ListenNetCfg: ds.ListenNet, - utils.ListenCfg: ds.Listen, - utils.DictionariesPathCfg: ds.DictionariesPath, - utils.OriginHostCfg: ds.OriginHost, - utils.OriginRealmCfg: ds.OriginRealm, - utils.VendorIDCfg: ds.VendorId, - utils.ProductNameCfg: ds.ProductName, - utils.ConcurrentRequestsCfg: ds.ConcurrentReqs, - utils.SyncedConnReqsCfg: ds.SyncedConnReqs, - utils.ASRTemplateCfg: ds.ASRTemplate, - utils.RARTemplateCfg: ds.RARTemplate, - utils.ForcedDisconnectCfg: ds.ForcedDisconnect, + utils.EnabledCfg: da.Enabled, + utils.ListenNetCfg: da.ListenNet, + utils.ListenCfg: da.Listen, + utils.DictionariesPathCfg: da.DictionariesPath, + utils.OriginHostCfg: da.OriginHost, + utils.OriginRealmCfg: da.OriginRealm, + utils.VendorIDCfg: da.VendorID, + utils.ProductNameCfg: da.ProductName, + utils.ConcurrentRequestsCfg: da.ConcurrentReqs, + utils.SyncedConnReqsCfg: da.SyncedConnReqs, + utils.ASRTemplateCfg: da.ASRTemplate, + utils.RARTemplateCfg: da.RARTemplate, + utils.ForcedDisconnectCfg: da.ForcedDisconnect, } - requestProcessors := make([]map[string]interface{}, len(ds.RequestProcessors)) - for i, item := range ds.RequestProcessors { + requestProcessors := make([]map[string]interface{}, len(da.RequestProcessors)) + for i, item := range da.RequestProcessors { requestProcessors[i] = item.AsMapInterface(separator) } initialMP[utils.RequestProcessorsCfg] = requestProcessors - if ds.SessionSConns != nil { - sessionSConns := make([]string, len(ds.SessionSConns)) - for i, item := range ds.SessionSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - if item == buf { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + if da.SessionSConns != nil { + sessionSConns := make([]string, len(da.SessionSConns)) + for i, item := range da.SessionSConns { + sessionSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns } return } + +// Clone returns a deep copy of DiameterAgentCfg +func (da DiameterAgentCfg) Clone() (cln *DiameterAgentCfg) { + cln = &DiameterAgentCfg{ + Enabled: da.Enabled, + ListenNet: da.ListenNet, + Listen: da.Listen, + DictionariesPath: da.DictionariesPath, + OriginHost: da.OriginHost, + OriginRealm: da.OriginRealm, + VendorID: da.VendorID, + ProductName: da.ProductName, + ConcurrentReqs: da.ConcurrentReqs, + SyncedConnReqs: da.SyncedConnReqs, + ASRTemplate: da.ASRTemplate, + RARTemplate: da.RARTemplate, + ForcedDisconnect: da.ForcedDisconnect, + } + if da.SessionSConns != nil { + cln.SessionSConns = make([]string, len(da.SessionSConns)) + for i, con := range da.SessionSConns { + cln.SessionSConns[i] = con + } + } + if da.RequestProcessors != nil { + cln.RequestProcessors = make([]*RequestProcessor, len(da.RequestProcessors)) + for i, req := range da.RequestProcessors { + cln.RequestProcessors[i] = req.Clone() + } + } + return +} diff --git a/config/diametercfg_test.go b/config/diametercfg_test.go index c34bf12be..061f7190d 100644 --- a/config/diametercfg_test.go +++ b/config/diametercfg_test.go @@ -56,7 +56,7 @@ func TestDiameterAgentCfgloadFromJsonCfg(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, OriginHost: "CGR-DA", OriginRealm: "cgrates.org", - VendorId: 0, + VendorID: 0, ProductName: "randomName", ConcurrentReqs: 10, SyncedConnReqs: true, @@ -72,7 +72,7 @@ func TestDiameterAgentCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.diameterAgentCfg.loadFromJsonCfg(jsonCFG, jsnCfg.generalCfg.RSRSep); err != nil { + } else if err = jsnCfg.diameterAgentCfg.loadFromJSONCfg(jsonCFG, jsnCfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.diameterAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.diameterAgentCfg)) @@ -90,7 +90,7 @@ func TestRequestProcessorloadFromJsonCfg1(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err := jsonCfg.diameterAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err := jsonCfg.diameterAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -114,7 +114,7 @@ func TestRequestProcessorloadFromJsonCfg2(t *testing.T) { } if jsonCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil { t.Error(err) - } else if err = jsonCfg.diameterAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { + } else if err = jsonCfg.diameterAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } } @@ -233,3 +233,38 @@ func TestDiameterAgentCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", eMap, rcv) } } + +func TestDiameterAgentCfgClone(t *testing.T) { + ban := &DiameterAgentCfg{ + Enabled: true, + ListenNet: "tcp", + Listen: "127.0.0.1:3868", + DictionariesPath: "/usr/share/cgrates/diameter/dict/", + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + OriginHost: "CGR-DA", + OriginRealm: "cgrates.org", + VendorID: 0, + ProductName: "randomName", + ConcurrentReqs: 10, + SyncedConnReqs: true, + ASRTemplate: "randomTemplate", + RARTemplate: "randomTemplate", + ForcedDisconnect: "forced", + RequestProcessors: []*RequestProcessor{ + { + ID: "cgrates", + Timezone: "Local", + }, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RequestProcessors[0].ID = ""; ban.RequestProcessors[0].ID != "cgrates" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/dnsagentcfg_test.go b/config/dnsagentcfg_test.go index dca7d9ca6..4468890be 100644 --- a/config/dnsagentcfg_test.go +++ b/config/dnsagentcfg_test.go @@ -299,3 +299,35 @@ func TestRequestProcessorClone(t *testing.T) { t.Errorf("Expected clone to not modify the cloned") } } + +func TestDNSAgentCfgClone(t *testing.T) { + ban := &DNSAgentCfg{ + Enabled: true, + Listen: "127.0.0.1:2053", + ListenNet: "udp", + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + Timezone: "UTC", + RequestProcessors: []*RequestProcessor{ + { + ID: "OutboundAUTHDryRun", + Filters: []string{"*string:~*req.request_type:OutboundAUTH", "*string:~*req.Msisdn:497700056231"}, + Flags: utils.FlagsWithParamsFromSlice([]string{utils.MetaDryRun}), + Timezone: "UTC", + RequestFields: []*FCTemplate{}, + ReplyFields: []*FCTemplate{ + {Tag: "Allow", Path: "*rep.response.Allow", Type: "constant", Mandatory: true, Layout: utils.EmptyString}, + }, + }, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RequestProcessors[0].ID = ""; ban.RequestProcessors[0].ID != "OutboundAUTHDryRun" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/dnsagntcfg.go b/config/dnsagntcfg.go index 2bdd588b1..c23c96658 100644 --- a/config/dnsagntcfg.go +++ b/config/dnsagntcfg.go @@ -19,8 +19,6 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) @@ -100,10 +98,9 @@ func (da *DNSAgentCfg) AsMapInterface(separator string) (initialMP map[string]in if da.SessionSConns != nil { sessionSConns := make([]string, len(da.SessionSConns)) for i, item := range da.SessionSConns { + sessionSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns @@ -111,6 +108,29 @@ func (da *DNSAgentCfg) AsMapInterface(separator string) (initialMP map[string]in return } +// Clone returns a deep copy of DNSAgentCfg +func (da DNSAgentCfg) Clone() (cln *DNSAgentCfg) { + cln = &DNSAgentCfg{ + Enabled: da.Enabled, + Listen: da.Listen, + ListenNet: da.ListenNet, + Timezone: da.Timezone, + } + if da.SessionSConns != nil { + cln.SessionSConns = make([]string, len(da.SessionSConns)) + for i, con := range da.SessionSConns { + cln.SessionSConns[i] = con + } + } + if da.RequestProcessors != nil { + cln.RequestProcessors = make([]*RequestProcessor, len(da.RequestProcessors)) + for i, req := range da.RequestProcessors { + cln.RequestProcessors[i] = req.Clone() + } + } + return +} + // RequestProcessor is the request processor configuration type RequestProcessor struct { ID string diff --git a/config/eescfg.go b/config/eescfg.go index 56caebcce..cec00df66 100644 --- a/config/eescfg.go +++ b/config/eescfg.go @@ -292,13 +292,13 @@ func (eeC EventExporterCfg) Clone() (cln *EventExporterCfg) { Opts: make(map[string]interface{}), } - if len(eeC.Filters) != 0 { + if eeC.Filters != nil { cln.Filters = make([]string, len(eeC.Filters)) for idx, val := range eeC.Filters { cln.Filters[idx] = val } } - if len(eeC.AttributeSIDs) != 0 { + if eeC.AttributeSIDs != nil { cln.AttributeSIDs = make([]string, len(eeC.AttributeSIDs)) for idx, val := range eeC.AttributeSIDs { cln.AttributeSIDs[idx] = val diff --git a/config/eescfg_test.go b/config/eescfg_test.go index 035307e51..c0c222082 100644 --- a/config/eescfg_test.go +++ b/config/eescfg_test.go @@ -84,8 +84,8 @@ func TestEESClone(t *testing.T) { Attempts: 1, Timezone: utils.EmptyString, AttributeSCtx: utils.EmptyString, - Filters: nil, - AttributeSIDs: nil, + Filters: []string{}, + AttributeSIDs: []string{}, Flags: utils.FlagsWithParams{}, Fields: []*FCTemplate{}, contentFields: []*FCTemplate{}, @@ -320,15 +320,16 @@ func TestEventExporterSameID(t *testing.T) { Opts: make(map[string]interface{}), }, { - ID: "file_exporter1", - Type: utils.MetaFileCSV, - FieldSep: ",", - Tenant: nil, - Timezone: utils.EmptyString, - Filters: nil, - ExportPath: "/var/spool/cgrates/ees", - Attempts: 1, - Flags: utils.FlagsWithParams{}, + ID: "file_exporter1", + Type: utils.MetaFileCSV, + FieldSep: ",", + Tenant: nil, + Timezone: utils.EmptyString, + Filters: []string{}, + AttributeSIDs: []string{}, + ExportPath: "/var/spool/cgrates/ees", + Attempts: 1, + Flags: utils.FlagsWithParams{}, Fields: []*FCTemplate{ {Tag: "CustomTag2", Path: "*exp.CustomPath2", Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("CustomValue2", utils.INFIELD_SEP), Mandatory: true, Layout: time.RFC3339}, diff --git a/config/filterscfg.go b/config/filterscfg.go index fbcbc98bd..dddbe4254 100644 --- a/config/filterscfg.go +++ b/config/filterscfg.go @@ -19,18 +19,17 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) +// FilterSCfg the filters config section type FilterSCfg struct { StatSConns []string ResourceSConns []string ApierSConns []string } -func (fSCfg *FilterSCfg) loadFromJsonCfg(jsnCfg *FilterSJsonCfg) (err error) { +func (fSCfg *FilterSCfg) loadFromJSONCfg(jsnCfg *FilterSJsonCfg) (err error) { if jsnCfg == nil { return } @@ -38,10 +37,9 @@ func (fSCfg *FilterSCfg) loadFromJsonCfg(jsnCfg *FilterSJsonCfg) (err error) { fSCfg.StatSConns = make([]string, len(*jsnCfg.Stats_conns)) for idx, connID := range *jsnCfg.Stats_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + fSCfg.StatSConns[idx] = connID if connID == utils.MetaInternal { fSCfg.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) - } else { - fSCfg.StatSConns[idx] = connID } } } @@ -49,10 +47,9 @@ func (fSCfg *FilterSCfg) loadFromJsonCfg(jsnCfg *FilterSJsonCfg) (err error) { fSCfg.ResourceSConns = make([]string, len(*jsnCfg.Resources_conns)) for idx, connID := range *jsnCfg.Resources_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + fSCfg.ResourceSConns[idx] = connID if connID == utils.MetaInternal { fSCfg.ResourceSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources) - } else { - fSCfg.ResourceSConns[idx] = connID } } } @@ -60,25 +57,24 @@ func (fSCfg *FilterSCfg) loadFromJsonCfg(jsnCfg *FilterSJsonCfg) (err error) { fSCfg.ApierSConns = make([]string, len(*jsnCfg.Apiers_conns)) for idx, connID := range *jsnCfg.Apiers_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + fSCfg.ApierSConns[idx] = connID if connID == utils.MetaInternal { fSCfg.ApierSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier) - } else { - fSCfg.ApierSConns[idx] = connID } } } return } +// AsMapInterface returns the config as a map[string]interface{} func (fSCfg *FilterSCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = make(map[string]interface{}) if fSCfg.StatSConns != nil { statSConns := make([]string, len(fSCfg.StatSConns)) for i, item := range fSCfg.StatSConns { + statSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) { - statSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaStatS) - } else { - statSConns[i] = item + statSConns[i] = utils.MetaInternal } } initialMP[utils.StatSConnsCfg] = statSConns @@ -86,10 +82,9 @@ func (fSCfg *FilterSCfg) AsMapInterface() (initialMP map[string]interface{}) { if fSCfg.ResourceSConns != nil { resourceSConns := make([]string, len(fSCfg.ResourceSConns)) for i, item := range fSCfg.ResourceSConns { + resourceSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources) { - resourceSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaResources) - } else { - resourceSConns[i] = item + resourceSConns[i] = utils.MetaInternal } } initialMP[utils.ResourceSConnsCfg] = resourceSConns @@ -97,13 +92,36 @@ func (fSCfg *FilterSCfg) AsMapInterface() (initialMP map[string]interface{}) { if fSCfg.ApierSConns != nil { apierConns := make([]string, len(fSCfg.ApierSConns)) for i, item := range fSCfg.ApierSConns { + apierConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier) { - apierConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaApier) - } else { - apierConns[i] = item + apierConns[i] = utils.MetaInternal } } initialMP[utils.ApierSConnsCfg] = apierConns } return } + +// Clone returns a deep copy of FilterSCfg +func (fSCfg FilterSCfg) Clone() (cln *FilterSCfg) { + cln = new(FilterSCfg) + if fSCfg.StatSConns != nil { + cln.StatSConns = make([]string, len(fSCfg.StatSConns)) + for i, con := range fSCfg.StatSConns { + cln.StatSConns[i] = con + } + } + if fSCfg.ResourceSConns != nil { + cln.ResourceSConns = make([]string, len(fSCfg.ResourceSConns)) + for i, con := range fSCfg.ResourceSConns { + cln.ResourceSConns[i] = con + } + } + if fSCfg.ApierSConns != nil { + cln.ApierSConns = make([]string, len(fSCfg.ApierSConns)) + for i, con := range fSCfg.ApierSConns { + cln.ApierSConns[i] = con + } + } + return +} diff --git a/config/filterscfg_test.go b/config/filterscfg_test.go index 829109b8d..a3f9d14da 100644 --- a/config/filterscfg_test.go +++ b/config/filterscfg_test.go @@ -37,7 +37,7 @@ func TestFilterSCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.filterSCfg.loadFromJsonCfg(cfgJSONS); err != nil { + } else if err = jsnCfg.filterSCfg.loadFromJSONCfg(cfgJSONS); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.filterSCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.filterSCfg)) @@ -79,3 +79,24 @@ func TestFilterSCfgAsMapInterface2(t *testing.T) { t.Errorf("Expected %+v, received %+v", eMap, rcv) } } + +func TestFilterSCfgClone(t *testing.T) { + ban := &FilterSCfg{ + StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "*conn1"}, + ResourceSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources), "*conn1"}, + ApierSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier), "*conn1"}, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.StatSConns[1] = ""; ban.StatSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ResourceSConns[1] = ""; ban.ResourceSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ApierSConns[1] = ""; ban.ApierSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/generalcfg.go b/config/generalcfg.go index 52dc40949..fa6f319aa 100644 --- a/config/generalcfg.go +++ b/config/generalcfg.go @@ -25,7 +25,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -// General config section +// GeneralCfg is the general config section type GeneralCfg struct { NodeID string // Identifier for this engine instance Logger string // dictates the way logs are displayed/stored @@ -54,8 +54,8 @@ type GeneralCfg struct { MaxParallelConns int // the maximum number of connection used by the *parallel strategy } -//loadFromJsonCfg loads General config from JsonCfg -func (gencfg *GeneralCfg) loadFromJsonCfg(jsnGeneralCfg *GeneralJsonCfg) (err error) { +// loadFromJSONCfg loads General config from JsonCfg +func (gencfg *GeneralCfg) loadFromJSONCfg(jsnGeneralCfg *GeneralJsonCfg) (err error) { if jsnGeneralCfg == nil { return nil } @@ -151,6 +151,7 @@ func (gencfg *GeneralCfg) loadFromJsonCfg(jsnGeneralCfg *GeneralJsonCfg) (err er return nil } +// AsMapInterface returns the config as a map[string]interface{} func (gencfg *GeneralCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.NodeIDCfg: gencfg.NodeID, @@ -172,41 +173,66 @@ func (gencfg *GeneralCfg) AsMapInterface() (initialMP map[string]interface{}) { utils.DigestEqualCfg: gencfg.DigestEqual, utils.RSRSepCfg: gencfg.RSRSep, utils.MaxParallelConnsCfg: gencfg.MaxParallelConns, + utils.LockingTimeoutCfg: "0", + utils.FailedPostsTTLCfg: "0", + utils.ConnectTimeoutCfg: "0", + utils.ReplyTimeoutCfg: "0", + utils.MinCallDurationCfg: "0", + utils.MaxCallDurationCfg: "0", } if gencfg.LockingTimeout != 0 { initialMP[utils.LockingTimeoutCfg] = gencfg.LockingTimeout.String() - } else { - initialMP[utils.LockingTimeoutCfg] = "0" } if gencfg.FailedPostsTTL != 0 { initialMP[utils.FailedPostsTTLCfg] = gencfg.FailedPostsTTL.String() - } else { - initialMP[utils.FailedPostsTTLCfg] = "0" } if gencfg.ConnectTimeout != 0 { initialMP[utils.ConnectTimeoutCfg] = gencfg.ConnectTimeout.String() - } else { - initialMP[utils.ConnectTimeoutCfg] = "0" } if gencfg.ReplyTimeout != 0 { initialMP[utils.ReplyTimeoutCfg] = gencfg.ReplyTimeout.String() - } else { - initialMP[utils.ReplyTimeoutCfg] = "0" } if gencfg.MinCallDuration != 0 { initialMP[utils.MinCallDurationCfg] = gencfg.MinCallDuration.String() - } else if gencfg.MinCallDuration == 0 { - initialMP[utils.MinCallDurationCfg] = "0" } if gencfg.MaxCallDuration != 0 { initialMP[utils.MaxCallDurationCfg] = gencfg.MaxCallDuration.String() - } else if gencfg.MaxCallDuration == 0 { - initialMP[utils.MaxCallDurationCfg] = "0" } return } + +// Clone returns a deep copy of GeneralCfg +func (gencfg GeneralCfg) Clone() *GeneralCfg { + return &GeneralCfg{ + NodeID: gencfg.NodeID, + Logger: gencfg.Logger, + LogLevel: gencfg.LogLevel, + RoundingDecimals: gencfg.RoundingDecimals, + DBDataEncoding: gencfg.DBDataEncoding, + TpExportPath: gencfg.TpExportPath, + PosterAttempts: gencfg.PosterAttempts, + FailedPostsDir: gencfg.FailedPostsDir, + FailedPostsTTL: gencfg.FailedPostsTTL, + DefaultReqType: gencfg.DefaultReqType, + DefaultCategory: gencfg.DefaultCategory, + DefaultTenant: gencfg.DefaultTenant, + DefaultTimezone: gencfg.DefaultTimezone, + DefaultCaching: gencfg.DefaultCaching, + ConnectAttempts: gencfg.ConnectAttempts, + Reconnects: gencfg.Reconnects, + ConnectTimeout: gencfg.ConnectTimeout, + ReplyTimeout: gencfg.ReplyTimeout, + LockingTimeout: gencfg.LockingTimeout, + MinCallDuration: gencfg.MinCallDuration, + MaxCallDuration: gencfg.MaxCallDuration, + DigestSeparator: gencfg.DigestSeparator, + DigestEqual: gencfg.DigestEqual, + RSRSep: gencfg.RSRSep, + MaxParallelConns: gencfg.MaxParallelConns, + } +} diff --git a/config/generalcfg_test.go b/config/generalcfg_test.go index 5047c9e8f..c5623382f 100644 --- a/config/generalcfg_test.go +++ b/config/generalcfg_test.go @@ -76,7 +76,7 @@ func TestGeneralCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.generalCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsnCfg.generalCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.generalCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.generalCfg)) @@ -90,7 +90,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -99,7 +99,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON1); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON1); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -108,7 +108,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON2); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON2); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -117,7 +117,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON3); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON3); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -126,7 +126,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON4); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON4); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -135,7 +135,7 @@ func TestGeneralParseDurationCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.generalCfg.loadFromJsonCfg(cfgJSON5); err == nil || err.Error() != expected { + } else if err = jsonCfg.generalCfg.loadFromJSONCfg(cfgJSON5); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %v", expected, err) } @@ -248,3 +248,39 @@ func TestGeneralCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, recevied %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } + +func TestGeneralCfgClone(t *testing.T) { + ban := &GeneralCfg{ + NodeID: "randomID", + Logger: utils.MetaSysLog, + LogLevel: 6, + RoundingDecimals: 5, + DBDataEncoding: "msgpack", + TpExportPath: "/var/spool/cgrates/tpe", + PosterAttempts: 3, + FailedPostsDir: "/var/spool/cgrates/failed_posts", + DefaultReqType: utils.META_RATED, + DefaultCategory: utils.CALL, + DefaultTenant: "cgrates.org", + DefaultTimezone: "Local", + ConnectAttempts: 3, + Reconnects: -1, + ConnectTimeout: time.Second, + ReplyTimeout: 2 * time.Second, + MinCallDuration: 0, + MaxCallDuration: 3 * time.Hour, + DigestSeparator: ",", + DigestEqual: ":", + MaxParallelConns: 100, + RSRSep: ";", + DefaultCaching: utils.MetaReload, + FailedPostsTTL: 2, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.NodeID = ""; ban.NodeID != "randomID" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/httpagntcfg.go b/config/httpagntcfg.go index 1f5046d5b..c384dbed1 100644 --- a/config/httpagntcfg.go +++ b/config/httpagntcfg.go @@ -22,14 +22,15 @@ import ( "github.com/cgrates/cgrates/utils" ) -type HttpAgentCfgs []*HttpAgentCfg +// HTTPAgentCfgs the config section for HTTP Agent +type HTTPAgentCfgs []*HTTPAgentCfg -func (hcfgs *HttpAgentCfgs) loadFromJsonCfg(jsnHttpAgntCfg *[]*HttpAgentJsonCfg, separator string) (err error) { - if jsnHttpAgntCfg == nil { +func (hcfgs *HTTPAgentCfgs) loadFromJSONCfg(jsnHTTPAgntCfg *[]*HttpAgentJsonCfg, separator string) (err error) { + if jsnHTTPAgntCfg == nil { return nil } - for _, jsnCfg := range *jsnHttpAgntCfg { - hac := new(HttpAgentCfg) + for _, jsnCfg := range *jsnHTTPAgntCfg { + hac := new(HTTPAgentCfg) var haveID bool if jsnCfg.Id != nil { for _, val := range *hcfgs { @@ -41,7 +42,7 @@ func (hcfgs *HttpAgentCfgs) loadFromJsonCfg(jsnHttpAgntCfg *[]*HttpAgentJsonCfg, } } - if err := hac.loadFromJsonCfg(jsnCfg, separator); err != nil { + if err := hac.loadFromJSONCfg(jsnCfg, separator); err != nil { return err } if !haveID { @@ -51,7 +52,8 @@ func (hcfgs *HttpAgentCfgs) loadFromJsonCfg(jsnHttpAgntCfg *[]*HttpAgentJsonCfg, return nil } -func (hcfgs HttpAgentCfgs) AsMapInterface(separator string) (mp []map[string]interface{}) { +// AsMapInterface returns the config as a map[string]interface{} +func (hcfgs HTTPAgentCfgs) AsMapInterface(separator string) (mp []map[string]interface{}) { mp = make([]map[string]interface{}, len(hcfgs)) for i, item := range hcfgs { mp[i] = item.AsMapInterface(separator) @@ -59,16 +61,29 @@ func (hcfgs HttpAgentCfgs) AsMapInterface(separator string) (mp []map[string]int return } -type HttpAgentCfg struct { +// Clone returns a deep copy of HTTPAgentCfgs +func (hcfgs HTTPAgentCfgs) Clone() (cln HTTPAgentCfgs) { + if hcfgs == nil { + return + } + cln = make(HTTPAgentCfgs, len(hcfgs)) + for i, h := range hcfgs { + cln[i] = h.Clone() + } + return +} + +// HTTPAgentCfg the config for a HTTP Agent +type HTTPAgentCfg struct { ID string // identifier for the agent, so we can update it's processors - Url string + URL string SessionSConns []string RequestPayload string ReplyPayload string RequestProcessors []*RequestProcessor } -func (ca *HttpAgentCfg) appendHttpAgntProcCfgs(hps *[]*ReqProcessorJsnCfg, separator string) (err error) { +func (ha *HTTPAgentCfg) appendHTTPAgntProcCfgs(hps *[]*ReqProcessorJsnCfg, separator string) (err error) { if hps == nil { return } @@ -76,7 +91,7 @@ func (ca *HttpAgentCfg) appendHttpAgntProcCfgs(hps *[]*ReqProcessorJsnCfg, separ rp := new(RequestProcessor) var haveID bool if reqProcJsn.ID != nil { - for _, rpSet := range ca.RequestProcessors { + for _, rpSet := range ha.RequestProcessors { if rpSet.ID == *reqProcJsn.ID { rp = rpSet // Will load data into the one set haveID = true @@ -88,58 +103,80 @@ func (ca *HttpAgentCfg) appendHttpAgntProcCfgs(hps *[]*ReqProcessorJsnCfg, separ return } if !haveID { - ca.RequestProcessors = append(ca.RequestProcessors, rp) + ha.RequestProcessors = append(ha.RequestProcessors, rp) } } return } -func (ca *HttpAgentCfg) loadFromJsonCfg(jsnCfg *HttpAgentJsonCfg, separator string) (err error) { +func (ha *HTTPAgentCfg) loadFromJSONCfg(jsnCfg *HttpAgentJsonCfg, separator string) (err error) { if jsnCfg == nil { return nil } if jsnCfg.Id != nil { - ca.ID = *jsnCfg.Id + ha.ID = *jsnCfg.Id } if jsnCfg.Url != nil { - ca.Url = *jsnCfg.Url + ha.URL = *jsnCfg.Url } if jsnCfg.Sessions_conns != nil { - ca.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) + ha.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, connID := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem if connID == utils.MetaInternal { - ca.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) + ha.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) } else { - ca.SessionSConns[idx] = connID + ha.SessionSConns[idx] = connID } } } if jsnCfg.Request_payload != nil { - ca.RequestPayload = *jsnCfg.Request_payload + ha.RequestPayload = *jsnCfg.Request_payload } if jsnCfg.Reply_payload != nil { - ca.ReplyPayload = *jsnCfg.Reply_payload + ha.ReplyPayload = *jsnCfg.Reply_payload } - if err = ca.appendHttpAgntProcCfgs(jsnCfg.Request_processors, separator); err != nil { + if err = ha.appendHTTPAgntProcCfgs(jsnCfg.Request_processors, separator); err != nil { return err } return nil } -func (ca *HttpAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { +// AsMapInterface returns the config as a map[string]interface{} +func (ha *HTTPAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.IDCfg: ca.ID, - utils.URLCfg: ca.Url, - utils.SessionSConnsCfg: ca.SessionSConns, - utils.RequestPayloadCfg: ca.RequestPayload, - utils.ReplyPayloadCfg: ca.ReplyPayload, + utils.IDCfg: ha.ID, + utils.URLCfg: ha.URL, + utils.SessionSConnsCfg: ha.SessionSConns, + utils.RequestPayloadCfg: ha.RequestPayload, + utils.ReplyPayloadCfg: ha.ReplyPayload, } - requestProcessors := make([]map[string]interface{}, len(ca.RequestProcessors)) - for i, item := range ca.RequestProcessors { + requestProcessors := make([]map[string]interface{}, len(ha.RequestProcessors)) + for i, item := range ha.RequestProcessors { requestProcessors[i] = item.AsMapInterface(separator) } initialMP[utils.RequestProcessorsCfg] = requestProcessors return } + +// Clone returns a deep copy of HTTPAgentCfg +func (ha HTTPAgentCfg) Clone() (cln *HTTPAgentCfg) { + cln = &HTTPAgentCfg{ + ID: ha.ID, + URL: ha.URL, + RequestPayload: ha.RequestPayload, + ReplyPayload: ha.ReplyPayload, + RequestProcessors: make([]*RequestProcessor, len(ha.RequestProcessors)), + } + if ha.SessionSConns != nil { + cln.SessionSConns = make([]string, len(ha.SessionSConns)) + for i, con := range ha.SessionSConns { + cln.SessionSConns[i] = con + } + } + for i, req := range ha.RequestProcessors { + cln.RequestProcessors[i] = req.Clone() + } + return +} diff --git a/config/httpagntcfg_test.go b/config/httpagntcfg_test.go index 15c599f7d..6d7e98512 100644 --- a/config/httpagntcfg_test.go +++ b/config/httpagntcfg_test.go @@ -54,10 +54,10 @@ func TestHttpAgentCfgsloadFromJsonCfgCase1(t *testing.T) { }, }, } - expected := HttpAgentCfgs{ + expected := HTTPAgentCfgs{ { ID: "RandomID", - Url: "/randomURL", + URL: "/randomURL", SessionSConns: []string{"*internal:*sessions"}, RequestPayload: "*url", ReplyPayload: "*xml", @@ -81,7 +81,7 @@ func TestHttpAgentCfgsloadFromJsonCfgCase1(t *testing.T) { expected[0].RequestProcessors[0].ReplyFields[0].ComputePath() if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.httpAgentCfg.loadFromJsonCfg(cfgJSON, jsnCfg.generalCfg.RSRSep); err != nil { + } else if err = jsnCfg.httpAgentCfg.loadFromJSONCfg(cfgJSON, jsnCfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(&expected, &jsnCfg.httpAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.httpAgentCfg)) @@ -158,10 +158,10 @@ func TestHttpAgentCfgsloadFromJsonCfgCase2(t *testing.T) { }, }, } - expected := HttpAgentCfgs{ - &HttpAgentCfg{ + expected := HTTPAgentCfgs{ + &HTTPAgentCfg{ ID: "conecto1", - Url: "/conecto", + URL: "/conecto", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: utils.MetaUrl, ReplyPayload: utils.MetaXml, @@ -203,9 +203,9 @@ func TestHttpAgentCfgsloadFromJsonCfgCase2(t *testing.T) { Layout: time.RFC3339, }}, }}, - }, &HttpAgentCfg{ + }, &HTTPAgentCfg{ ID: "conecto_xml", - Url: "/conecto_xml", + URL: "/conecto_xml", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: utils.MetaXml, ReplyPayload: utils.MetaXml, @@ -222,7 +222,7 @@ func TestHttpAgentCfgsloadFromJsonCfgCase2(t *testing.T) { expected[0].RequestProcessors[1].RequestFields[0].ComputePath() if cfgJsn, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = cfgJsn.httpAgentCfg.loadFromJsonCfg(cfgJSON, cfgJsn.generalCfg.RSRSep); err != nil { + } else if err = cfgJsn.httpAgentCfg.loadFromJSONCfg(cfgJSON, cfgJsn.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, cfgJsn.httpAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfgJsn.httpAgentCfg)) @@ -247,9 +247,9 @@ func TestHttpAgentCfgloadFromJsonCfgCase3(t *testing.T) { }, }, } - expected := HttpAgentCfg{ + expected := HTTPAgentCfg{ ID: "conecto1", - Url: "/conecto", + URL: "/conecto", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: "*url", ReplyPayload: "*xml", @@ -262,8 +262,8 @@ func TestHttpAgentCfgloadFromJsonCfgCase3(t *testing.T) { ReplyFields: []*FCTemplate{}, }}, } - var httpcfg HttpAgentCfg - if err = httpcfg.loadFromJsonCfg(jsnhttpCfg, utils.INFIELD_SEP); err != nil { + var httpcfg HTTPAgentCfg + if err = httpcfg.loadFromJSONCfg(jsnhttpCfg, utils.INFIELD_SEP); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, httpcfg) { t.Errorf("Expected: %+v \n, received: %+v", utils.ToJSON(expected), utils.ToJSON(httpcfg)) @@ -343,7 +343,7 @@ func TestHttpAgentCfgloadFromJsonCfgCase4(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.httpAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err = jsonCfg.httpAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -358,7 +358,7 @@ func TestHttpAgentCfgloadFromJsonCfgCase5(t *testing.T) { if err != nil { t.Error(err) } - if err := jsonCfg.httpAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { + if err := jsonCfg.httpAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } } @@ -368,8 +368,8 @@ func TestHttpAgentCfgloadFromJsonCfgCase6(t *testing.T) { if err != nil { t.Error(err) } - httpAgentCfg := new(HttpAgentCfg) - if err := httpAgentCfg.loadFromJsonCfg(nil, jsonCfg.generalCfg.RSRSep); err != nil { + httpAgentCfg := new(HTTPAgentCfg) + if err := httpAgentCfg.loadFromJSONCfg(nil, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } } @@ -387,14 +387,14 @@ func TestHttpAgentCfgloadFromJsonCfgCase7(t *testing.T) { Id: utils.StringPointer("RandomID"), }, } - expected := HttpAgentCfgs{ + expected := HTTPAgentCfgs{ { ID: "RandomID", }, } if jsnCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil { t.Error(err) - } else if err = jsnCfg.httpAgentCfg.loadFromJsonCfg(cfgJSON, jsnCfg.generalCfg.RSRSep); err != nil { + } else if err = jsnCfg.httpAgentCfg.loadFromJSONCfg(cfgJSON, jsnCfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(&expected, &jsnCfg.httpAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.httpAgentCfg)) @@ -402,9 +402,9 @@ func TestHttpAgentCfgloadFromJsonCfgCase7(t *testing.T) { } func TestHttpAgentCfgappendHttpAgntProcCfgs(t *testing.T) { - initial := &HttpAgentCfg{ + initial := &HTTPAgentCfg{ ID: "conecto1", - Url: "/conecto", + URL: "/conecto", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: "*url", ReplyPayload: "*xml", @@ -452,9 +452,9 @@ func TestHttpAgentCfgappendHttpAgntProcCfgs(t *testing.T) { }}, }, } - expected := &HttpAgentCfg{ + expected := &HTTPAgentCfg{ ID: "conecto1", - Url: "/conecto", + URL: "/conecto", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: "*url", ReplyPayload: "*xml", @@ -490,7 +490,7 @@ func TestHttpAgentCfgappendHttpAgntProcCfgs(t *testing.T) { } expected.RequestProcessors[0].ReplyFields[0].ComputePath() expected.RequestProcessors[1].ReplyFields[0].ComputePath() - if err = initial.appendHttpAgntProcCfgs(proceses, utils.INFIELD_SEP); err != nil { + if err = initial.appendHTTPAgntProcCfgs(proceses, utils.INFIELD_SEP); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, initial) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(expected), utils.ToJSON(initial)) @@ -563,3 +563,40 @@ func TestHttpAgentCfgAsMapInterface(t *testing.T) { t.Errorf("Expected %+v, recieved %+v", eMap, rcv) } } + +func TestHTTPAgentCfgsClone(t *testing.T) { + ban := HTTPAgentCfgs{ + { + ID: "RandomID", + URL: "/randomURL", + SessionSConns: []string{"*internal:*sessions", "*conn1"}, + RequestPayload: "*url", + ReplyPayload: "*xml", + RequestProcessors: []*RequestProcessor{{ + ID: "OutboundAUTHDryRun", + Filters: []string{"*string:*req.request_type:OutboundAUTH", "*string:*req.Msisdn:497700056231"}, + Tenant: NewRSRParsersMustCompile("cgrates.org", utils.INFIELD_SEP), + Flags: utils.FlagsWithParams{utils.MetaDryRun: {}}, + RequestFields: []*FCTemplate{}, + ReplyFields: []*FCTemplate{{ + Tag: "Allow", + Path: "response.Allow", + Type: "*constant", + Value: NewRSRParsersMustCompile("1", utils.INFIELD_SEP), + Mandatory: true, + Layout: time.RFC3339, + }}, + }}, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv[0].SessionSConns[1] = ""; ban[0].SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv[0].RequestProcessors[0].ID = ""; ban[0].RequestProcessors[0].ID != "OutboundAUTHDryRun" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/httpcfg.go b/config/httpcfg.go index 8caec6dd7..3bd08d68b 100644 --- a/config/httpcfg.go +++ b/config/httpcfg.go @@ -34,40 +34,41 @@ type HTTPCfg struct { ClientOpts map[string]interface{} } -// loadFromJsonCfg loads Database config from JsonCfg -func (httpcfg *HTTPCfg) loadFromJsonCfg(jsnHttpCfg *HTTPJsonCfg) (err error) { - if jsnHttpCfg == nil { +// loadFromJSONCfg loads Database config from JsonCfg +func (httpcfg *HTTPCfg) loadFromJSONCfg(jsnHTTPCfg *HTTPJsonCfg) (err error) { + if jsnHTTPCfg == nil { return nil } - if jsnHttpCfg.Json_rpc_url != nil { - httpcfg.HTTPJsonRPCURL = *jsnHttpCfg.Json_rpc_url + if jsnHTTPCfg.Json_rpc_url != nil { + httpcfg.HTTPJsonRPCURL = *jsnHTTPCfg.Json_rpc_url } - if jsnHttpCfg.Dispatchers_registrar_url != nil { - httpcfg.DispatchersRegistrarURL = *jsnHttpCfg.Dispatchers_registrar_url + if jsnHTTPCfg.Dispatchers_registrar_url != nil { + httpcfg.DispatchersRegistrarURL = *jsnHTTPCfg.Dispatchers_registrar_url } - if jsnHttpCfg.Ws_url != nil { - httpcfg.HTTPWSURL = *jsnHttpCfg.Ws_url + if jsnHTTPCfg.Ws_url != nil { + httpcfg.HTTPWSURL = *jsnHTTPCfg.Ws_url } - if jsnHttpCfg.Freeswitch_cdrs_url != nil { - httpcfg.HTTPFreeswitchCDRsURL = *jsnHttpCfg.Freeswitch_cdrs_url + if jsnHTTPCfg.Freeswitch_cdrs_url != nil { + httpcfg.HTTPFreeswitchCDRsURL = *jsnHTTPCfg.Freeswitch_cdrs_url } - if jsnHttpCfg.Http_Cdrs != nil { - httpcfg.HTTPCDRsURL = *jsnHttpCfg.Http_Cdrs + if jsnHTTPCfg.Http_Cdrs != nil { + httpcfg.HTTPCDRsURL = *jsnHTTPCfg.Http_Cdrs } - if jsnHttpCfg.Use_basic_auth != nil { - httpcfg.HTTPUseBasicAuth = *jsnHttpCfg.Use_basic_auth + if jsnHTTPCfg.Use_basic_auth != nil { + httpcfg.HTTPUseBasicAuth = *jsnHTTPCfg.Use_basic_auth } - if jsnHttpCfg.Auth_users != nil { - httpcfg.HTTPAuthUsers = *jsnHttpCfg.Auth_users + if jsnHTTPCfg.Auth_users != nil { + httpcfg.HTTPAuthUsers = *jsnHTTPCfg.Auth_users } - if jsnHttpCfg.Client_opts != nil { - for k, v := range jsnHttpCfg.Client_opts { + if jsnHTTPCfg.Client_opts != nil { + for k, v := range jsnHTTPCfg.Client_opts { httpcfg.ClientOpts[k] = v } } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (httpcfg *HTTPCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.HTTPJsonRPCURLCfg: httpcfg.HTTPJsonRPCURL, @@ -81,3 +82,24 @@ func (httpcfg *HTTPCfg) AsMapInterface() (initialMP map[string]interface{}) { } return } + +// Clone returns a deep copy of HTTPCfg +func (httpcfg HTTPCfg) Clone() (cln *HTTPCfg) { + cln = &HTTPCfg{ + HTTPJsonRPCURL: httpcfg.HTTPJsonRPCURL, + DispatchersRegistrarURL: httpcfg.DispatchersRegistrarURL, + HTTPWSURL: httpcfg.HTTPWSURL, + HTTPFreeswitchCDRsURL: httpcfg.HTTPFreeswitchCDRsURL, + HTTPCDRsURL: httpcfg.HTTPCDRsURL, + HTTPUseBasicAuth: httpcfg.HTTPUseBasicAuth, + HTTPAuthUsers: make(map[string]string), + ClientOpts: make(map[string]interface{}), + } + for u, a := range httpcfg.HTTPAuthUsers { + cln.HTTPAuthUsers[u] = a + } + for o, val := range httpcfg.ClientOpts { + cln.ClientOpts[o] = val + } + return +} diff --git a/config/httpcfg_test.go b/config/httpcfg_test.go index 77b9be70c..7543e4de6 100644 --- a/config/httpcfg_test.go +++ b/config/httpcfg_test.go @@ -61,7 +61,7 @@ func TestHTTPCfgloadFromJsonCfg(t *testing.T) { } if cfgJsn, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = cfgJsn.httpCfg.loadFromJsonCfg(cfgJSONStr); err != nil { + } else if err = cfgJsn.httpCfg.loadFromJSONCfg(cfgJSONStr); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, cfgJsn.httpCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfgJsn.httpCfg)) @@ -147,3 +147,30 @@ func TestHTTPCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v, received %+v", eMap, rcv) } } + +func TestHTTPCfgClone(t *testing.T) { + ban := &HTTPCfg{ + HTTPJsonRPCURL: "/jsonrpc", + HTTPWSURL: "/ws", + DispatchersRegistrarURL: "/randomUrl", + HTTPFreeswitchCDRsURL: "/freeswitch_json", + HTTPCDRsURL: "/cdr_http", + HTTPUseBasicAuth: false, + HTTPAuthUsers: map[string]string{ + "user": "pass", + }, + ClientOpts: map[string]interface{}{ + utils.HTTPClientTLSClientConfigCfg: false, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.ClientOpts[utils.HTTPClientTLSClientConfigCfg] = ""; ban.ClientOpts[utils.HTTPClientTLSClientConfigCfg] != false { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.HTTPAuthUsers["user"] = ""; ban.HTTPAuthUsers["user"] != "pass" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/kamagentcfg.go b/config/kamagentcfg.go index e3d3216bd..1b34644a6 100644 --- a/config/kamagentcfg.go +++ b/config/kamagentcfg.go @@ -19,44 +19,60 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) -// Represents one connection instance towards Kamailio +// NewDfltKamConnConfig returns the first cached default value for a KamConnCfg connection +func NewDfltKamConnConfig() *KamConnCfg { + if dfltKamConnConfig == nil { + return new(KamConnCfg) // No defaults, most probably we are building the defaults now + } + dfltVal := *dfltKamConnConfig + return &dfltVal +} + +// KamConnCfg represents one connection instance towards Kamailio type KamConnCfg struct { Alias string Address string Reconnects int } -func (self *KamConnCfg) loadFromJsonCfg(jsnCfg *KamConnJsonCfg) error { +func (kamCfg *KamConnCfg) loadFromJSONCfg(jsnCfg *KamConnJsonCfg) error { if jsnCfg == nil { return nil } if jsnCfg.Address != nil { - self.Address = *jsnCfg.Address + kamCfg.Address = *jsnCfg.Address } if jsnCfg.Alias != nil { - self.Alias = *jsnCfg.Alias + kamCfg.Alias = *jsnCfg.Alias } if jsnCfg.Reconnects != nil { - self.Reconnects = *jsnCfg.Reconnects + kamCfg.Reconnects = *jsnCfg.Reconnects } return nil } -func (kamCfg *KamConnCfg) AsMapInterface() (initialMP map[string]interface{}) { - initialMP = map[string]interface{}{ +// AsMapInterface returns the config as a map[string]interface{} +func (kamCfg *KamConnCfg) AsMapInterface() map[string]interface{} { + return map[string]interface{}{ utils.AliasCfg: kamCfg.Alias, utils.AddressCfg: kamCfg.Address, utils.ReconnectsCfg: kamCfg.Reconnects, } - return } -// SM-Kamailio config section +// Clone returns a deep copy of KamConnCfg +func (kamCfg KamConnCfg) Clone() *KamConnCfg { + return &KamConnCfg{ + Alias: kamCfg.Alias, + Address: kamCfg.Address, + Reconnects: kamCfg.Reconnects, + } +} + +// KamAgentCfg is the Kamailio config section type KamAgentCfg struct { Enabled bool SessionSConns []string @@ -65,7 +81,7 @@ type KamAgentCfg struct { Timezone string } -func (ka *KamAgentCfg) loadFromJsonCfg(jsnCfg *KamAgentJsonCfg) error { +func (ka *KamAgentCfg) loadFromJSONCfg(jsnCfg *KamAgentJsonCfg) error { if jsnCfg == nil { return nil } @@ -76,10 +92,9 @@ func (ka *KamAgentCfg) loadFromJsonCfg(jsnCfg *KamAgentJsonCfg) error { ka.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, attrConn := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + ka.SessionSConns[idx] = attrConn if attrConn == utils.MetaInternal { ka.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - } else { - ka.SessionSConns[idx] = attrConn } } } @@ -90,7 +105,7 @@ func (ka *KamAgentCfg) loadFromJsonCfg(jsnCfg *KamAgentJsonCfg) error { ka.EvapiConns = make([]*KamConnCfg, len(*jsnCfg.Evapi_conns)) for idx, jsnConnCfg := range *jsnCfg.Evapi_conns { ka.EvapiConns[idx] = NewDfltKamConnConfig() - ka.EvapiConns[idx].loadFromJsonCfg(jsnConnCfg) + ka.EvapiConns[idx].loadFromJSONCfg(jsnConnCfg) } } if jsnCfg.Timezone != nil { @@ -99,6 +114,7 @@ func (ka *KamAgentCfg) loadFromJsonCfg(jsnCfg *KamAgentJsonCfg) error { return nil } +// AsMapInterface returns the config as a map[string]interface{} func (ka *KamAgentCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: ka.Enabled, @@ -115,13 +131,34 @@ func (ka *KamAgentCfg) AsMapInterface() (initialMP map[string]interface{}) { if ka.SessionSConns != nil { sessionSConns := make([]string, len(ka.SessionSConns)) for i, item := range ka.SessionSConns { + sessionSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns } return } + +// Clone returns a deep copy of KamAgentCfg +func (ka KamAgentCfg) Clone() (cln *KamAgentCfg) { + cln = &KamAgentCfg{ + Enabled: ka.Enabled, + CreateCdr: ka.CreateCdr, + Timezone: ka.Timezone, + } + if ka.SessionSConns != nil { + cln.SessionSConns = make([]string, len(ka.SessionSConns)) + for i, con := range ka.SessionSConns { + cln.SessionSConns[i] = con + } + } + if ka.EvapiConns != nil { + cln.EvapiConns = make([]*KamConnCfg, len(ka.EvapiConns)) + for i, req := range ka.EvapiConns { + cln.EvapiConns[i] = req.Clone() + } + } + return +} diff --git a/config/kamagentcfg_test.go b/config/kamagentcfg_test.go index aa948bbab..33559fd24 100644 --- a/config/kamagentcfg_test.go +++ b/config/kamagentcfg_test.go @@ -25,7 +25,7 @@ import ( ) func TestKamAgentCfgloadFromJsonCfg(t *testing.T) { - cfgJson := &KamAgentJsonCfg{ + cfgJSON := &KamAgentJsonCfg{ Enabled: utils.BoolPointer(true), Sessions_conns: &[]string{"*internal"}, Create_cdr: utils.BoolPointer(true), @@ -47,7 +47,7 @@ func TestKamAgentCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.kamAgentCfg.loadFromJsonCfg(cfgJson); err != nil { + } else if err = jsnCfg.kamAgentCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.kamAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.kamAgentCfg)) @@ -56,12 +56,12 @@ func TestKamAgentCfgloadFromJsonCfg(t *testing.T) { func TestKamConnCfgloadFromJsonCfg(t *testing.T) { var kamcocfg, expected KamConnCfg - if err := kamcocfg.loadFromJsonCfg(nil); err != nil { + if err := kamcocfg.loadFromJSONCfg(nil); err != nil { t.Error(err) } else if !reflect.DeepEqual(kamcocfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, kamcocfg) } - if err := kamcocfg.loadFromJsonCfg(new(KamConnJsonCfg)); err != nil { + if err := kamcocfg.loadFromJSONCfg(new(KamConnJsonCfg)); err != nil { t.Error(err) } else if !reflect.DeepEqual(kamcocfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, kamcocfg) @@ -74,7 +74,7 @@ func TestKamConnCfgloadFromJsonCfg(t *testing.T) { Address: "127.0.0.1:8448", Reconnects: 5, } - if err = kamcocfg.loadFromJsonCfg(json); err != nil { + if err = kamcocfg.loadFromJSONCfg(json); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, kamcocfg) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(expected), utils.ToJSON(kamcocfg)) @@ -127,3 +127,23 @@ func TestKamAgentCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", eMap, rcv) } } + +func TestKamAgentCfgClone(t *testing.T) { + ban := &KamAgentCfg{ + Enabled: true, + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + CreateCdr: true, + EvapiConns: []*KamConnCfg{{Address: "127.0.0.1:8448", Reconnects: 10, Alias: "randomAlias"}}, + Timezone: "Local", + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.EvapiConns[0].Alias = ""; ban.EvapiConns[0].Alias != "randomAlias" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/listencfg.go b/config/listencfg.go index 537746e8e..95114b2a5 100644 --- a/config/listencfg.go +++ b/config/listencfg.go @@ -20,7 +20,7 @@ package config import "github.com/cgrates/cgrates/utils" -// Listen config section +// ListenCfg is the listen config section type ListenCfg struct { RPCJSONListen string // RPC JSON listening address RPCGOBListen string // RPC GOB listening address @@ -30,8 +30,8 @@ type ListenCfg struct { HTTPTLSListen string // HTTP TLS listening address } -//loadFromJsonCfg loads Database config from JsonCfg -func (lstcfg *ListenCfg) loadFromJsonCfg(jsnListenCfg *ListenJsonCfg) (err error) { +// loadFromJSONCfg loads Database config from JsonCfg +func (lstcfg *ListenCfg) loadFromJSONCfg(jsnListenCfg *ListenJsonCfg) (err error) { if jsnListenCfg == nil { return nil } @@ -56,8 +56,9 @@ func (lstcfg *ListenCfg) loadFromJsonCfg(jsnListenCfg *ListenJsonCfg) (err error return nil } -func (lstcfg *ListenCfg) AsMapInterface() (initialMP map[string]interface{}) { - initialMP = map[string]interface{}{ +// AsMapInterface returns the config as a map[string]interface{} +func (lstcfg *ListenCfg) AsMapInterface() map[string]interface{} { + return map[string]interface{}{ utils.RPCJSONListenCfg: lstcfg.RPCJSONListen, utils.RPCGOBListenCfg: lstcfg.RPCGOBListen, utils.HTTPListenCfg: lstcfg.HTTPListen, @@ -65,5 +66,16 @@ func (lstcfg *ListenCfg) AsMapInterface() (initialMP map[string]interface{}) { utils.RPCGOBTLSListenCfg: lstcfg.RPCGOBTLSListen, utils.HTTPTLSListenCfg: lstcfg.HTTPTLSListen, } - return +} + +// Clone returns a deep copy of ListenCfg +func (lstcfg ListenCfg) Clone() *ListenCfg { + return &ListenCfg{ + RPCJSONListen: lstcfg.RPCJSONListen, + RPCGOBListen: lstcfg.RPCGOBListen, + HTTPListen: lstcfg.HTTPListen, + RPCJSONTLSListen: lstcfg.RPCJSONTLSListen, + RPCGOBTLSListen: lstcfg.RPCGOBTLSListen, + HTTPTLSListen: lstcfg.HTTPTLSListen, + } } diff --git a/config/listencfg_test.go b/config/listencfg_test.go index 8bd9b5b2a..be92eadc7 100644 --- a/config/listencfg_test.go +++ b/config/listencfg_test.go @@ -43,7 +43,7 @@ func TestListenCfgloadFromJsonCfg(t *testing.T) { } if jsnCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsnCfg.listenCfg.loadFromJsonCfg(jsonCfg); err != nil { + } else if err = jsnCfg.listenCfg.loadFromJSONCfg(jsonCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsnCfg.listenCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsnCfg.listenCfg)) @@ -93,3 +93,21 @@ func TestListenCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v, received %+v", eMap, rcv) } } + +func TestListenCfgClone(t *testing.T) { + ban := &ListenCfg{ + RPCJSONListen: "127.0.0.1:2012", + RPCGOBListen: "127.0.0.1:2013", + HTTPListen: "127.0.0.1:2080", + RPCJSONTLSListen: "127.0.0.1:2022", + RPCGOBTLSListen: "127.0.0.1:2023", + HTTPTLSListen: "127.0.0.1:2280", + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.RPCJSONListen = ""; ban.RPCJSONListen != "127.0.0.1:2012" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/loaderscfg.go b/config/loaderscfg.go index ef24f9600..8e50da459 100644 --- a/config/loaderscfg.go +++ b/config/loaderscfg.go @@ -19,12 +19,12 @@ along with this program. If not, see package config import ( - "strings" "time" "github.com/cgrates/cgrates/utils" ) +// NewDfltLoaderSCfg returns the first cached default value for a LoaderSCfg connection func NewDfltLoaderSCfg() *LoaderSCfg { if dfltLoaderConfig == nil { return new(LoaderSCfg) @@ -36,6 +36,7 @@ func NewDfltLoaderSCfg() *LoaderSCfg { // LoaderSCfgs to export some methods for LoaderS profiles type LoaderSCfgs []*LoaderSCfg +// AsMapInterface returns the config as a map[string]interface{} func (ldrs LoaderSCfgs) AsMapInterface(separator string) (loaderCfg []map[string]interface{}) { loaderCfg = make([]map[string]interface{}, len(ldrs)) for i, item := range ldrs { @@ -54,8 +55,18 @@ func (ldrs LoaderSCfgs) Enabled() bool { return false } +// Clone itself into a new LoaderSCfgs +func (ldrs LoaderSCfgs) Clone() (cln LoaderSCfgs) { + cln = make(LoaderSCfgs, len(ldrs)) + for i, ldr := range ldrs { + cln[i] = ldr.Clone() + } + return +} + +// LoaderSCfg the config for a loader type LoaderSCfg struct { - Id string + ID string Enabled bool Tenant RSRParsers DryRun bool @@ -68,138 +79,144 @@ type LoaderSCfg struct { Data []*LoaderDataType } -type LoaderDataType struct { //rename to LoaderDataType +// LoaderDataType the template for profile loading +type LoaderDataType struct { Type string Filename string Flags utils.FlagsWithParams Fields []*FCTemplate } -func (self *LoaderDataType) loadFromJsonCfg(jsnCfg *LoaderJsonDataType, msgTemplates map[string][]*FCTemplate, separator string) (err error) { +func (lData *LoaderDataType) loadFromJSONCfg(jsnCfg *LoaderJsonDataType, msgTemplates map[string][]*FCTemplate, separator string) (err error) { if jsnCfg == nil { return nil } if jsnCfg.Type != nil { - self.Type = *jsnCfg.Type + lData.Type = *jsnCfg.Type } if jsnCfg.File_name != nil { - self.Filename = *jsnCfg.File_name + lData.Filename = *jsnCfg.File_name } if jsnCfg.Flags != nil { - self.Flags = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags) + lData.Flags = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags) } if jsnCfg.Fields != nil { - if self.Fields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Fields, separator); err != nil { + if lData.Fields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Fields, separator); err != nil { return } - if tpls, err := InflateTemplates(self.Fields, msgTemplates); err != nil { + if tpls, err := InflateTemplates(lData.Fields, msgTemplates); err != nil { return err } else if tpls != nil { - self.Fields = tpls + lData.Fields = tpls } } return nil } -func (self *LoaderSCfg) loadFromJsonCfg(jsnCfg *LoaderJsonCfg, msgTemplates map[string][]*FCTemplate, separator string) (err error) { +func (l *LoaderSCfg) loadFromJSONCfg(jsnCfg *LoaderJsonCfg, msgTemplates map[string][]*FCTemplate, separator string) (err error) { if jsnCfg == nil { return nil } if jsnCfg.ID != nil { - self.Id = *jsnCfg.ID + l.ID = *jsnCfg.ID } if jsnCfg.Enabled != nil { - self.Enabled = *jsnCfg.Enabled + l.Enabled = *jsnCfg.Enabled } if jsnCfg.Tenant != nil { - if self.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, separator); err != nil { + if l.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, separator); err != nil { return err } } if jsnCfg.Dry_run != nil { - self.DryRun = *jsnCfg.Dry_run + l.DryRun = *jsnCfg.Dry_run } if jsnCfg.Run_delay != nil { - if self.RunDelay, err = utils.ParseDurationWithNanosecs(*jsnCfg.Run_delay); err != nil { + if l.RunDelay, err = utils.ParseDurationWithNanosecs(*jsnCfg.Run_delay); err != nil { return } } if jsnCfg.Lock_filename != nil { - self.LockFileName = *jsnCfg.Lock_filename + l.LockFileName = *jsnCfg.Lock_filename } if jsnCfg.Caches_conns != nil { - self.CacheSConns = make([]string, len(*jsnCfg.Caches_conns)) + l.CacheSConns = make([]string, len(*jsnCfg.Caches_conns)) for idx, connID := range *jsnCfg.Caches_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem if connID == utils.MetaInternal { - self.CacheSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches) + l.CacheSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches) } else { - self.CacheSConns[idx] = connID + l.CacheSConns[idx] = connID } } } if jsnCfg.Field_separator != nil { - self.FieldSeparator = *jsnCfg.Field_separator + l.FieldSeparator = *jsnCfg.Field_separator } if jsnCfg.Tp_in_dir != nil { - self.TpInDir = *jsnCfg.Tp_in_dir + l.TpInDir = *jsnCfg.Tp_in_dir } if jsnCfg.Tp_out_dir != nil { - self.TpOutDir = *jsnCfg.Tp_out_dir + l.TpOutDir = *jsnCfg.Tp_out_dir } if jsnCfg.Data != nil { data := make([]*LoaderDataType, len(*jsnCfg.Data)) for idx, jsnLoCfg := range *jsnCfg.Data { data[idx] = new(LoaderDataType) - if err := data[idx].loadFromJsonCfg(jsnLoCfg, msgTemplates, separator); err != nil { + if err := data[idx].loadFromJSONCfg(jsnLoCfg, msgTemplates, separator); err != nil { return err } } - self.Data = data + l.Data = data } 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 { +func (lData LoaderDataType) Clone() (cln *LoaderDataType) { + cln = &LoaderDataType{ + Type: lData.Type, + Filename: lData.Filename, + Flags: lData.Flags.Clone(), + Fields: make([]*FCTemplate, len(lData.Fields)), + } + for idx, val := range lData.Fields { cln.Fields[idx] = val.Clone() } - return cln + return } // Clone itself into a new LoadersConfig -func (self *LoaderSCfg) Clone() *LoaderSCfg { - clnLoader := new(LoaderSCfg) - clnLoader.Id = self.Id - clnLoader.Enabled = self.Enabled - clnLoader.Tenant = self.Tenant - clnLoader.DryRun = self.DryRun - clnLoader.RunDelay = self.RunDelay - clnLoader.LockFileName = self.LockFileName - clnLoader.CacheSConns = make([]string, len(self.CacheSConns)) - for idx, connID := range self.CacheSConns { - clnLoader.CacheSConns[idx] = connID +func (l LoaderSCfg) Clone() (cln *LoaderSCfg) { + cln = &LoaderSCfg{ + ID: l.ID, + Enabled: l.Enabled, + Tenant: l.Tenant, + DryRun: l.DryRun, + RunDelay: l.RunDelay, + LockFileName: l.LockFileName, + CacheSConns: make([]string, len(l.CacheSConns)), + FieldSeparator: l.FieldSeparator, + TpInDir: l.TpInDir, + TpOutDir: l.TpOutDir, + Data: make([]*LoaderDataType, len(l.Data)), } - clnLoader.FieldSeparator = self.FieldSeparator - clnLoader.TpInDir = self.TpInDir - clnLoader.TpOutDir = self.TpOutDir - clnLoader.Data = make([]*LoaderDataType, len(self.Data)) - for idx, fld := range self.Data { - clnLoader.Data[idx] = fld.Clone() + for idx, connID := range l.CacheSConns { + cln.CacheSConns[idx] = connID } - return clnLoader + for idx, fld := range l.Data { + cln.Data[idx] = fld.Clone() + } + return } +// AsMapInterface returns the config as a map[string]interface{} func (lData *LoaderDataType) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.TypeCf: lData.Type, utils.FilenameCfg: lData.Filename, + utils.FlagsCfg: lData.Flags.SliceFlags(), } fields := make([]map[string]interface{}, len(lData.Fields)) @@ -207,13 +224,14 @@ func (lData *LoaderDataType) AsMapInterface(separator string) (initialMP map[str fields[i] = item.AsMapInterface(separator) } initialMP[utils.FieldsCfg] = fields - return } +// AsMapInterface returns the config as a map[string]interface{} func (l *LoaderSCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.IDCfg: l.Id, + utils.IDCfg: l.ID, + utils.TenantCfg: l.Tenant.GetRule(separator), utils.EnabledCfg: l.Enabled, utils.DryRunCfg: l.DryRun, utils.LockFileNameCfg: l.LockFileName, @@ -222,11 +240,6 @@ func (l *LoaderSCfg) AsMapInterface(separator string) (initialMP map[string]inte utils.TpOutDirCfg: l.TpOutDir, utils.RunDelayCfg: "0", } - tenant := make([]string, len(l.Tenant)) - for i, item := range l.Tenant { - tenant[i] = item.Rules - } - initialMP[utils.TenantCfg] = strings.Join(tenant, utils.EmptyString) if l.Data != nil { data := make([]map[string]interface{}, len(l.Data)) for i, item := range l.Data { @@ -240,10 +253,9 @@ func (l *LoaderSCfg) AsMapInterface(separator string) (initialMP map[string]inte if l.CacheSConns != nil { cacheSConns := make([]string, len(l.CacheSConns)) for i, item := range l.CacheSConns { + cacheSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches) { - cacheSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaCaches) - } else { - cacheSConns[i] = item + cacheSConns[i] = utils.MetaInternal } } initialMP[utils.CachesConnsCfg] = cacheSConns diff --git a/config/loaderscfg_test.go b/config/loaderscfg_test.go index 7193e7080..a8faf8f4e 100644 --- a/config/loaderscfg_test.go +++ b/config/loaderscfg_test.go @@ -61,7 +61,7 @@ func TestLoaderSCfgloadFromJsonCfgCase1(t *testing.T) { expected := LoaderSCfgs{ { Enabled: true, - Id: utils.MetaDefault, + ID: utils.MetaDefault, Tenant: ten, LockFileName: ".cgr.lck", CacheSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "*conn1"}, @@ -108,9 +108,9 @@ func TestLoaderSCfgloadFromJsonCfgCase2(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.loaderCfg[0].loadFromJsonCfg(nil, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err != nil { + } else if err = jsonCfg.loaderCfg[0].loadFromJSONCfg(nil, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) - } else if err = jsonCfg.loaderCfg[0].loadFromJsonCfg(cfgJSON, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err = jsonCfg.loaderCfg[0].loadFromJSONCfg(cfgJSON, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -130,7 +130,7 @@ func TestLoaderSCfgloadFromJsonCfgCase3(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err := jsonCfg.loaderCfg[0].loadFromJsonCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err := jsonCfg.loaderCfg[0].loadFromJSONCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -150,7 +150,7 @@ func TestLoaderSCfgloadFromJsonCfgCase4(t *testing.T) { expected := "no template with id: <>" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.loaderCfg[0].loadFromJsonCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err = jsonCfg.loaderCfg[0].loadFromJSONCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -200,7 +200,7 @@ func TestLoaderSCfgloadFromJsonCfgCase5(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.loaderCfg[0].loadFromJsonCfg(cfg, msgTemplates, jsonCfg.generalCfg.RSRSep); err != nil { + } else if err = jsonCfg.loaderCfg[0].loadFromJSONCfg(cfg, msgTemplates, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(jsonCfg.loaderCfg[0].Data[0].Fields[0], expectedFields[0].Data[0].Fields[0]) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expectedFields[0].Data[0].Fields[0]), utils.ToJSON(jsonCfg.loaderCfg[0].Data[0].Fields[0])) @@ -213,7 +213,7 @@ func TestLoaderSCfgloadFromJsonCfgCase6(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.loaderCfg[0].loadFromJsonCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err != nil { + } else if err = jsonCfg.loaderCfg[0].loadFromJSONCfg(cfg, jsonCfg.templates, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } } @@ -409,3 +409,43 @@ func TestLoaderCfgAsMapInterfaceCase2(t *testing.T) { t.Errorf("Expected %+v, received %+v", rcv[0][utils.Tenant], eMap[0][utils.Tenant]) } } + +func TestLoaderSCfgsClone(t *testing.T) { + ban := LoaderSCfgs{{ + Enabled: true, + ID: utils.MetaDefault, + Tenant: NewRSRParsersMustCompile("cgrate.org", utils.INFIELD_SEP), + LockFileName: ".cgr.lck", + CacheSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "*conn1"}, + FieldSeparator: ",", + TpInDir: "/var/spool/cgrates/loader/in", + TpOutDir: "/var/spool/cgrates/loader/out", + Data: []*LoaderDataType{{ + Type: "*attributes", + Filename: "Attributes.csv", + Flags: utils.FlagsWithParams{}, + Fields: []*FCTemplate{ + { + Tag: "TenantID", + Path: "Tenant", + pathSlice: []string{"Tenant"}, + pathItems: utils.PathItems{{Field: "Tenant"}}, + Type: utils.META_COMPOSED, + Value: NewRSRParsersMustCompile("cgrate.org", utils.INFIELD_SEP), + Mandatory: true, + Layout: time.RFC3339, + }, + }}, + }, + }} + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv[0].CacheSConns[1] = ""; ban[0].CacheSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv[0].Data[0].Type = ""; ban[0].Data[0].Type != "*attributes" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/multifiles_it_test.go b/config/multifiles_it_test.go index 04f0144b1..ba6fc07d2 100644 --- a/config/multifiles_it_test.go +++ b/config/multifiles_it_test.go @@ -87,10 +87,10 @@ func TestMfHttpAgentMultipleFields(t *testing.T) { if len(mfCgrCfg.HTTPAgentCfg()) != 2 { t.Errorf("Expected: 2, received: %+v", len(mfCgrCfg.HTTPAgentCfg())) } - expected := HttpAgentCfgs{ + expected := HTTPAgentCfgs{ { ID: "conecto1", - Url: "/newConecto", + URL: "/newConecto", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: "*url", ReplyPayload: "*xml", @@ -163,7 +163,7 @@ func TestMfHttpAgentMultipleFields(t *testing.T) { }, { ID: "conecto_xml", - Url: "/conecto_xml", + URL: "/conecto_xml", SessionSConns: []string{utils.MetaLocalHost}, RequestPayload: "*xml", ReplyPayload: "*xml", diff --git a/config/radiuscfg.go b/config/radiuscfg.go index 918e5eb5a..422619517 100644 --- a/config/radiuscfg.go +++ b/config/radiuscfg.go @@ -19,11 +19,10 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) +// RadiusAgentCfg the config section that describes the Radius Agent type RadiusAgentCfg struct { Enabled bool ListenNet string // udp or tcp @@ -35,46 +34,45 @@ type RadiusAgentCfg struct { RequestProcessors []*RequestProcessor } -func (self *RadiusAgentCfg) loadFromJsonCfg(jsnCfg *RadiusAgentJsonCfg, separator string) (err error) { +func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg, separator string) (err error) { if jsnCfg == nil { return nil } if jsnCfg.Enabled != nil { - self.Enabled = *jsnCfg.Enabled + ra.Enabled = *jsnCfg.Enabled } if jsnCfg.Listen_net != nil { - self.ListenNet = *jsnCfg.Listen_net + ra.ListenNet = *jsnCfg.Listen_net } if jsnCfg.Listen_auth != nil { - self.ListenAuth = *jsnCfg.Listen_auth + ra.ListenAuth = *jsnCfg.Listen_auth } if jsnCfg.Listen_acct != nil { - self.ListenAcct = *jsnCfg.Listen_acct + ra.ListenAcct = *jsnCfg.Listen_acct } if jsnCfg.Client_secrets != nil { - if self.ClientSecrets == nil { - self.ClientSecrets = make(map[string]string) + if ra.ClientSecrets == nil { + ra.ClientSecrets = make(map[string]string) } for k, v := range *jsnCfg.Client_secrets { - self.ClientSecrets[k] = v + ra.ClientSecrets[k] = v } } if jsnCfg.Client_dictionaries != nil { - if self.ClientDictionaries == nil { - self.ClientDictionaries = make(map[string]string) + if ra.ClientDictionaries == nil { + ra.ClientDictionaries = make(map[string]string) } for k, v := range *jsnCfg.Client_dictionaries { - self.ClientDictionaries[k] = v + ra.ClientDictionaries[k] = v } } if jsnCfg.Sessions_conns != nil { - self.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) + ra.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, attrConn := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + ra.SessionSConns[idx] = attrConn if attrConn == utils.MetaInternal { - self.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - } else { - self.SessionSConns[idx] = attrConn + ra.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) } } } @@ -82,7 +80,7 @@ func (self *RadiusAgentCfg) loadFromJsonCfg(jsnCfg *RadiusAgentJsonCfg, separato for _, reqProcJsn := range *jsnCfg.Request_processors { rp := new(RequestProcessor) var haveID bool - for _, rpSet := range self.RequestProcessors { + for _, rpSet := range ra.RequestProcessors { if reqProcJsn.ID != nil && rpSet.ID == *reqProcJsn.ID { rp = rpSet // Will load data into the one set haveID = true @@ -93,34 +91,22 @@ func (self *RadiusAgentCfg) loadFromJsonCfg(jsnCfg *RadiusAgentJsonCfg, separato return } if !haveID { - self.RequestProcessors = append(self.RequestProcessors, rp) + ra.RequestProcessors = append(ra.RequestProcessors, rp) } } } return } +// AsMapInterface returns the config as a map[string]interface{} func (ra *RadiusAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.EnabledCfg: ra.Enabled, - utils.ListenNetCfg: ra.ListenNet, - utils.ListenAuthCfg: ra.ListenAuth, - utils.ListenAcctCfg: ra.ListenAcct, - } - if ra.ClientSecrets != nil { - clientSecrets := make(map[string]interface{}, len(ra.ClientSecrets)) - for key, val := range ra.ClientSecrets { - clientSecrets[key] = val - } - initialMP[utils.ClientSecretsCfg] = clientSecrets - } - - if ra.ClientDictionaries != nil { - clientDictionaries := make(map[string]interface{}, len(ra.ClientDictionaries)) - for key, val := range ra.ClientDictionaries { - clientDictionaries[key] = val - } - initialMP[utils.ClientDictionariesCfg] = clientDictionaries + utils.EnabledCfg: ra.Enabled, + utils.ListenNetCfg: ra.ListenNet, + utils.ListenAuthCfg: ra.ListenAuth, + utils.ListenAcctCfg: ra.ListenAcct, + utils.ClientSecretsCfg: ra.ClientSecrets, + utils.ClientDictionariesCfg: ra.ClientDictionaries, } requestProcessors := make([]map[string]interface{}, len(ra.RequestProcessors)) @@ -132,13 +118,43 @@ func (ra *RadiusAgentCfg) AsMapInterface(separator string) (initialMP map[string if ra.SessionSConns != nil { sessionSConns := make([]string, len(ra.SessionSConns)) for i, item := range ra.SessionSConns { + sessionSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns } return } + +// Clone returns a deep copy of RadiusAgentCfg +func (ra RadiusAgentCfg) Clone() (cln *RadiusAgentCfg) { + cln = &RadiusAgentCfg{ + Enabled: ra.Enabled, + ListenNet: ra.ListenNet, + ListenAuth: ra.ListenAuth, + ListenAcct: ra.ListenAcct, + ClientSecrets: make(map[string]string), + ClientDictionaries: make(map[string]string), + } + if ra.SessionSConns != nil { + cln.SessionSConns = make([]string, len(ra.SessionSConns)) + for i, con := range ra.SessionSConns { + cln.SessionSConns[i] = con + } + } + for k, v := range ra.ClientSecrets { + cln.ClientSecrets[k] = v + } + for k, v := range ra.ClientDictionaries { + cln.ClientDictionaries[k] = v + } + if ra.RequestProcessors != nil { + cln.RequestProcessors = make([]*RequestProcessor, len(ra.RequestProcessors)) + for i, req := range ra.RequestProcessors { + cln.RequestProcessors[i] = req.Clone() + } + } + return +} diff --git a/config/radiuscfg_test.go b/config/radiuscfg_test.go index 7bc310e0f..9acfd50c5 100644 --- a/config/radiuscfg_test.go +++ b/config/radiuscfg_test.go @@ -89,7 +89,7 @@ func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) { } if cfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = cfg.radiusAgentCfg.loadFromJsonCfg(cfgJSON, cfg.generalCfg.RSRSep); err != nil { + } else if err = cfg.radiusAgentCfg.loadFromJSONCfg(cfgJSON, cfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, cfg.radiusAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfg.radiusAgentCfg)) @@ -122,7 +122,7 @@ func TestRadiusAgentCfgloadFromJsonCfgCase2(t *testing.T) { } if jsonCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil { t.Error(err) - } else if err = jsonCfg.radiusAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { + } else if err = jsonCfg.radiusAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err != nil { t.Error(err) } else if !reflect.DeepEqual(jsonCfg.radiusAgentCfg.RequestProcessors[0].ID, expected.RequestProcessors[0].ID) { t.Errorf("Expected %+v, received %+v", utils.ToJSON(jsonCfg.radiusAgentCfg.RequestProcessors[0].ID), @@ -141,7 +141,7 @@ func TestRadiusAgentCfgloadFromJsonCfgCase3(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.radiusAgentCfg.loadFromJsonCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { + } else if err = jsonCfg.radiusAgentCfg.loadFromJSONCfg(cfgJSON, jsonCfg.generalCfg.RSRSep); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -176,10 +176,10 @@ func TestRadiusAgentCfgAsMapInterface(t *testing.T) { utils.ListenNetCfg: "udp", utils.ListenAuthCfg: "127.0.0.1:1816", utils.ListenAcctCfg: "127.0.0.1:1892", - utils.ClientSecretsCfg: map[string]interface{}{ + utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, - utils.ClientDictionariesCfg: map[string]interface{}{ + utils.ClientDictionariesCfg: map[string]string{ utils.MetaDefault: "/usr/share/cgrates/", }, utils.SessionSConnsCfg: []string{"*conn1", "*conn2"}, @@ -213,10 +213,10 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) { utils.ListenNetCfg: "udp", utils.ListenAuthCfg: "127.0.0.1:1812", utils.ListenAcctCfg: "127.0.0.1:1813", - utils.ClientSecretsCfg: map[string]interface{}{ + utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, - utils.ClientDictionariesCfg: map[string]interface{}{ + utils.ClientDictionariesCfg: map[string]string{ utils.MetaDefault: "/usr/share/cgrates/radius/dict/", }, utils.SessionSConnsCfg: []string{"*internal"}, @@ -228,3 +228,51 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } + +func TestRadiusAgentCfgClone(t *testing.T) { + ban := &RadiusAgentCfg{ + Enabled: true, + ListenNet: "udp", + ListenAuth: "127.0.0.1:1812", + ListenAcct: "127.0.0.1:1813", + ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"}, + ClientDictionaries: map[string]string{utils.MetaDefault: "/usr/share/cgrates/radius/dict/"}, + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + RequestProcessors: []*RequestProcessor{ + { + ID: "OutboundAUTHDryRun", + Filters: []string{"*string:~*req.request_type:OutboundAUTH", "*string:~*req.Msisdn:497700056231"}, + Flags: utils.FlagsWithParams{utils.MetaDryRun: {}}, + Timezone: utils.EmptyString, + Tenant: NewRSRParsersMustCompile("~*req.CGRID", utils.INFIELD_SEP), + RequestFields: []*FCTemplate{}, + ReplyFields: []*FCTemplate{ + { + Tag: "Allow", + Path: "*rep.response.Allow", + Type: utils.META_CONSTANT, + Value: NewRSRParsersMustCompile("1", utils.INFIELD_SEP), + Mandatory: true, + Layout: time.RFC3339, + }, + }, + }, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RequestProcessors[0].ID = ""; ban.RequestProcessors[0].ID != "OutboundAUTHDryRun" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ClientSecrets[utils.MetaDefault] = ""; ban.ClientSecrets[utils.MetaDefault] != "CGRateS.org" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ClientDictionaries[utils.MetaDefault] = ""; ban.ClientDictionaries[utils.MetaDefault] != "/usr/share/cgrates/radius/dict/" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/ralscfg.go b/config/ralscfg.go index 9292ced5d..91f0d0bd7 100644 --- a/config/ralscfg.go +++ b/config/ralscfg.go @@ -20,13 +20,12 @@ package config import ( "strconv" - "strings" "time" "github.com/cgrates/cgrates/utils" ) -// Rater config section +// RalsCfg is rater config section type RalsCfg struct { Enabled bool // start standalone server (no balancer) ThresholdSConns []string // address where to reach ThresholdS config @@ -40,8 +39,8 @@ type RalsCfg struct { DynaprepaidActionPlans []string } -//loadFromJsonCfg loads Rals config from JsonCfg -func (ralsCfg *RalsCfg) loadFromJsonCfg(jsnRALsCfg *RalsJsonCfg) (err error) { +// loadFromJSONCfg loads Rals config from JsonCfg +func (ralsCfg *RalsCfg) loadFromJSONCfg(jsnRALsCfg *RalsJsonCfg) (err error) { if jsnRALsCfg == nil { return nil } @@ -52,10 +51,9 @@ func (ralsCfg *RalsCfg) loadFromJsonCfg(jsnRALsCfg *RalsJsonCfg) (err error) { ralsCfg.ThresholdSConns = make([]string, len(*jsnRALsCfg.Thresholds_conns)) for idx, conn := range *jsnRALsCfg.Thresholds_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + ralsCfg.ThresholdSConns[idx] = conn if conn == utils.MetaInternal { ralsCfg.ThresholdSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } else { - ralsCfg.ThresholdSConns[idx] = conn } } } @@ -63,10 +61,9 @@ func (ralsCfg *RalsCfg) loadFromJsonCfg(jsnRALsCfg *RalsJsonCfg) (err error) { ralsCfg.StatSConns = make([]string, len(*jsnRALsCfg.Stats_conns)) for idx, conn := range *jsnRALsCfg.Stats_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + ralsCfg.StatSConns[idx] = conn if conn == utils.MetaInternal { ralsCfg.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) - } else { - ralsCfg.StatSConns[idx] = conn } } } @@ -74,10 +71,9 @@ func (ralsCfg *RalsCfg) loadFromJsonCfg(jsnRALsCfg *RalsJsonCfg) (err error) { ralsCfg.CacheSConns = make([]string, len(*jsnRALsCfg.CacheS_conns)) for idx, conn := range *jsnRALsCfg.CacheS_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + ralsCfg.CacheSConns[idx] = conn if conn == utils.MetaInternal { ralsCfg.CacheSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches) - } else { - ralsCfg.CacheSConns[idx] = conn } } } @@ -112,6 +108,7 @@ func (ralsCfg *RalsCfg) loadFromJsonCfg(jsnRALsCfg *RalsJsonCfg) (err error) { return nil } +// AsMapInterface returns the config as a map[string]interface{} func (ralsCfg *RalsCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: ralsCfg.Enabled, @@ -119,14 +116,14 @@ func (ralsCfg *RalsCfg) AsMapInterface() (initialMP map[string]interface{}) { utils.RemoveExpiredCfg: ralsCfg.RemoveExpired, utils.MaxIncrementsCfg: ralsCfg.MaxIncrements, utils.DynaprepaidActionplansCfg: ralsCfg.DynaprepaidActionPlans, + utils.BalanceRatingSubjectCfg: ralsCfg.BalanceRatingSubject, } if ralsCfg.ThresholdSConns != nil { threSholds := make([]string, len(ralsCfg.ThresholdSConns)) for i, item := range ralsCfg.ThresholdSConns { + threSholds[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { - threSholds[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaThresholds) - } else { - threSholds[i] = item + threSholds[i] = utils.MetaInternal } } initialMP[utils.ThresholdSConnsCfg] = threSholds @@ -134,42 +131,76 @@ func (ralsCfg *RalsCfg) AsMapInterface() (initialMP map[string]interface{}) { if ralsCfg.StatSConns != nil { statS := make([]string, len(ralsCfg.StatSConns)) for i, item := range ralsCfg.StatSConns { + statS[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) { - statS[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaStatS) - } else { - statS[i] = item + statS[i] = utils.MetaInternal } } initialMP[utils.StatSConnsCfg] = statS } - if ralsCfg.MaxComputedUsage != nil { - maxComputed := make(map[string]interface{}) - for key, item := range ralsCfg.MaxComputedUsage { - if key == utils.ANY || key == utils.VOICE { - maxComputed[key] = item.String() - } else { - maxComputed[key] = strconv.Itoa(int(item)) - } - } - initialMP[utils.MaxComputedUsageCfg] = maxComputed - } if ralsCfg.CacheSConns != nil { cacheSConns := make([]string, len(ralsCfg.CacheSConns)) for i, item := range ralsCfg.CacheSConns { + cacheSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches) { - cacheSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaCaches) - } else { - cacheSConns[i] = item + cacheSConns[i] = utils.MetaInternal } } initialMP[utils.CachesConnsCfg] = cacheSConns } - if ralsCfg.BalanceRatingSubject != nil { - balanceRating := make(map[string]interface{}) - for key, item := range ralsCfg.BalanceRatingSubject { - balanceRating[key] = item + maxComputed := make(map[string]interface{}) + for key, item := range ralsCfg.MaxComputedUsage { + if key == utils.ANY || key == utils.VOICE { + maxComputed[key] = item.String() + } else { + maxComputed[key] = strconv.Itoa(int(item)) } - initialMP[utils.BalanceRatingSubjectCfg] = balanceRating + } + initialMP[utils.MaxComputedUsageCfg] = maxComputed + return +} + +// Clone returns a deep copy of RalsCfg +func (ralsCfg RalsCfg) Clone() (cln *RalsCfg) { + cln = &RalsCfg{ + Enabled: ralsCfg.Enabled, + RpSubjectPrefixMatching: ralsCfg.RpSubjectPrefixMatching, + RemoveExpired: ralsCfg.RemoveExpired, + MaxIncrements: ralsCfg.MaxIncrements, + + MaxComputedUsage: make(map[string]time.Duration), + BalanceRatingSubject: make(map[string]string), + } + if ralsCfg.ThresholdSConns != nil { + cln.ThresholdSConns = make([]string, len(ralsCfg.ThresholdSConns)) + for i, con := range ralsCfg.ThresholdSConns { + cln.ThresholdSConns[i] = con + } + } + if ralsCfg.StatSConns != nil { + cln.StatSConns = make([]string, len(ralsCfg.StatSConns)) + for i, con := range ralsCfg.StatSConns { + cln.StatSConns[i] = con + } + } + if ralsCfg.CacheSConns != nil { + cln.CacheSConns = make([]string, len(ralsCfg.CacheSConns)) + for i, con := range ralsCfg.CacheSConns { + cln.CacheSConns[i] = con + } + } + if ralsCfg.DynaprepaidActionPlans != nil { + cln.DynaprepaidActionPlans = make([]string, len(ralsCfg.DynaprepaidActionPlans)) + for i, con := range ralsCfg.DynaprepaidActionPlans { + cln.DynaprepaidActionPlans[i] = con + } + } + + for k, u := range ralsCfg.MaxComputedUsage { + cln.MaxComputedUsage[k] = u + } + for k, r := range ralsCfg.BalanceRatingSubject { + cln.BalanceRatingSubject[k] = r } return } diff --git a/config/ralscfg_test.go b/config/ralscfg_test.go index b7bef963d..35d6086a6 100644 --- a/config/ralscfg_test.go +++ b/config/ralscfg_test.go @@ -68,12 +68,12 @@ func TestRalsCfgFromJsonCfgCase1(t *testing.T) { }, DynaprepaidActionPlans: []string{"randomPlans"}, } - if cfgJson, err := NewDefaultCGRConfig(); err != nil { + if cfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = cfgJson.ralsCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = cfg.ralsCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) - } else if !reflect.DeepEqual(expected, cfgJson.ralsCfg) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfgJson.ralsCfg)) + } else if !reflect.DeepEqual(expected, cfg.ralsCfg) { + t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfg.ralsCfg)) } } @@ -86,7 +86,7 @@ func TestRalsCfgFromJsonCfgCase2(t *testing.T) { expected := "time: unknown unit \"hh\" in duration \"189hh\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.ralsCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.ralsCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -120,7 +120,7 @@ func TestRalsCfgAsMapInterfaceCase1(t *testing.T) { "*mms": "10000", }, utils.MaxIncrementsCfg: 1000000, - utils.BalanceRatingSubjectCfg: map[string]interface{}{ + utils.BalanceRatingSubjectCfg: map[string]string{ "*any": "*zero1ns", "*voice": "*zero1s", }, @@ -155,7 +155,7 @@ func TestRalsCfgAsMapInterfaceCase2(t *testing.T) { "*mms": "10000", }, utils.MaxIncrementsCfg: 1000000, - utils.BalanceRatingSubjectCfg: map[string]interface{}{ + utils.BalanceRatingSubjectCfg: map[string]string{ "*any": "*zero1ns", "*voice": "*zero1s", }, @@ -167,3 +167,46 @@ func TestRalsCfgAsMapInterfaceCase2(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } + +func TestRalsCfgClone(t *testing.T) { + ban := &RalsCfg{ + Enabled: true, + ThresholdSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"}, + StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS), "*conn1"}, + CacheSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "*conn1"}, + RpSubjectPrefixMatching: true, + RemoveExpired: true, + MaxComputedUsage: map[string]time.Duration{ + utils.ANY: 189 * time.Hour, + utils.VOICE: 72 * time.Hour, + utils.DATA: 107374182400, + utils.SMS: 5000, + utils.MMS: 10000, + }, + MaxIncrements: 1000000, + BalanceRatingSubject: map[string]string{ + utils.META_ANY: "*zero1ns", + utils.META_VOICE: "*zero1s", + }, + DynaprepaidActionPlans: []string{"randomPlans"}, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.ThresholdSConns[1] = ""; ban.ThresholdSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.StatSConns[1] = ""; ban.StatSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.CacheSConns[1] = ""; ban.CacheSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.MaxComputedUsage[utils.ANY] = 0; ban.MaxComputedUsage[utils.ANY] != 189*time.Hour { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.BalanceRatingSubject[utils.META_ANY] = ""; ban.BalanceRatingSubject[utils.META_ANY] != "*zero1ns" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/rjreader.go b/config/rjreader.go index 5dd03667c..cf501b377 100644 --- a/config/rjreader.go +++ b/config/rjreader.go @@ -31,7 +31,7 @@ import ( ) // NewRjReader creates a new rjReader from a io.Reader -func NewRjReader(rdr io.Reader) (r *rjReader, err error) { +func NewRjReader(rdr io.Reader) (r *RjReader, err error) { var b []byte b, err = ioutil.ReadAll(rdr) if err != nil { @@ -41,8 +41,8 @@ func NewRjReader(rdr io.Reader) (r *rjReader, err error) { } // NewRjReaderFromBytes creates a new rjReader from a slice of bytes -func NewRjReaderFromBytes(b []byte) *rjReader { - return &rjReader{buf: b} +func NewRjReaderFromBytes(b []byte) *RjReader { + return &RjReader{buf: b} } // isNewLine check if byte is new line @@ -70,8 +70,8 @@ func isAlfanum(bit byte) bool { (bit >= '0' && bit <= '9') } -// structure that implements io.Reader to read json files ignoring C style comments and replacing *env: -type rjReader struct { +// RjReader structure that implements io.Reader to read json files ignoring C style comments and replacing *env: +type RjReader struct { buf []byte isInString bool // ignore character in strings indx int // used to parse the buffer @@ -79,7 +79,7 @@ type rjReader struct { } // Read implementation -func (rjr *rjReader) Read(p []byte) (n int, err error) { +func (rjr *RjReader) Read(p []byte) (n int, err error) { for n = range p { p[n], err = rjr.ReadByte() if !rjr.envOff && @@ -99,13 +99,13 @@ func (rjr *rjReader) Read(p []byte) (n int, err error) { } // Close implementation -func (rjr *rjReader) Close() error { +func (rjr *RjReader) Close() error { rjr.buf = nil return nil } // ReadByte implementation -func (rjr *rjReader) ReadByte() (bit byte, err error) { +func (rjr *RjReader) ReadByte() (bit byte, err error) { if rjr.isInString { //ignore commas in strings return rjr.ReadByteWC() } @@ -126,7 +126,8 @@ func (rjr *rjReader) ReadByte() (bit byte, err error) { return } -func (rjr *rjReader) UnreadByte() (err error) { +// UnreadByte implementation +func (rjr *RjReader) UnreadByte() (err error) { if rjr.indx <= 0 { return bufio.ErrInvalidUnreadByte } @@ -135,12 +136,12 @@ func (rjr *rjReader) UnreadByte() (err error) { } // returns true if the file was parsed completly -func (rjr *rjReader) isEndOfFile() bool { +func (rjr *RjReader) isEndOfFile() bool { return rjr.indx >= len(rjr.buf) } // consumeComent consumes the comment based on the peeked byte -func (rjr *rjReader) consumeComent(pkbit byte) (bool, error) { +func (rjr *RjReader) consumeComent(pkbit byte) (bool, error) { switch pkbit { case '/': for !rjr.isEndOfFile() { @@ -167,7 +168,7 @@ func (rjr *rjReader) consumeComent(pkbit byte) (bool, error) { } //readFirstNonWhiteSpace reads first non white space byte -func (rjr *rjReader) readFirstNonWhiteSpace() (bit byte, err error) { +func (rjr *RjReader) readFirstNonWhiteSpace() (bit byte, err error) { for !rjr.isEndOfFile() { bit = rjr.buf[rjr.indx] rjr.indx++ @@ -179,7 +180,7 @@ func (rjr *rjReader) readFirstNonWhiteSpace() (bit byte, err error) { } // ReadByteWC reads next byte skiping the comments -func (rjr *rjReader) ReadByteWC() (bit byte, err error) { +func (rjr *RjReader) ReadByteWC() (bit byte, err error) { if rjr.isEndOfFile() { return 0, io.EOF } @@ -209,7 +210,7 @@ func (rjr *rjReader) ReadByteWC() (bit byte, err error) { } // PeekByteWC peeks next byte skiping the comments -func (rjr *rjReader) PeekByteWC() (bit byte, err error) { +func (rjr *RjReader) PeekByteWC() (bit byte, err error) { for !rjr.isEndOfFile() { bit = rjr.buf[rjr.indx] if !rjr.isInString && rjr.indx+1 < len(rjr.buf) && bit == '/' { //try consume comment @@ -234,13 +235,13 @@ func (rjr *rjReader) PeekByteWC() (bit byte, err error) { } //checkMeta check if char mach with next char from MetaEnv if not reset the counting -func (rjr *rjReader) checkMeta() bool { +func (rjr *RjReader) checkMeta() bool { return rjr.indx-1+len(utils.MetaEnv) < len(rjr.buf) && utils.MetaEnv == string(rjr.buf[rjr.indx-1:rjr.indx-1+len(utils.MetaEnv)]) } //readEnvName reads the enviorment key -func (rjr *rjReader) readEnvName(indx int) (name []byte, endindx int) { //0 if not set +func (rjr *RjReader) readEnvName(indx int) (name []byte, endindx int) { //0 if not set for indx < len(rjr.buf) { //read byte by byte bit := rjr.buf[indx] if !isAlfanum(bit) && bit != '_' { //[a-zA-Z_]+[a-zA-Z0-9_]* @@ -253,7 +254,7 @@ func (rjr *rjReader) readEnvName(indx int) (name []byte, endindx int) { //0 if n } //replaceEnv replaces the EnvMeta and enviorment key with enviorment variable value in specific buffer -func (rjr *rjReader) replaceEnv(startEnv int) error { +func (rjr *RjReader) replaceEnv(startEnv int) error { midEnv := len(utils.MetaEnv) key, endEnv := rjr.readEnvName(startEnv + midEnv) value, err := ReadEnv(string(key)) @@ -264,8 +265,8 @@ func (rjr *rjReader) replaceEnv(startEnv int) error { return nil } -// warning: needs to read file again -func (rjr *rjReader) HandleJSONError(err error) error { +// HandleJSONError warning: needs to read file again +func (rjr *RjReader) HandleJSONError(err error) error { var offset int64 switch realErr := err.(type) { case nil: @@ -291,7 +292,7 @@ func (rjr *rjReader) HandleJSONError(err error) error { strings.Split(string(rjr.buf), "\n")[line-1]) } -func (rjr *rjReader) getJSONOffsetLine(offset int64) (line, character int64) { +func (rjr *RjReader) getJSONOffsetLine(offset int64) (line, character int64) { line = 1 // start line counting from 1 var lastChar byte @@ -411,8 +412,8 @@ func (rjr *rjReader) getJSONOffsetLine(offset int64) (line, character int64) { return } -// Loads the json config out of rjReader -func (rjr *rjReader) Decode(cfg interface{}) (err error) { +// Decode loads the json config out of rjReader +func (rjr *RjReader) Decode(cfg interface{}) (err error) { if err = json.NewDecoder(rjr).Decode(cfg); err != nil { return rjr.HandleJSONError(err) } diff --git a/config/rjreader_test.go b/config/rjreader_test.go index 3a8c8fd61..b8ef0c3a6 100644 --- a/config/rjreader_test.go +++ b/config/rjreader_test.go @@ -79,7 +79,7 @@ func TestNewRjReaderError(t *testing.T) { } func TestUnreadByte(t *testing.T) { - reader := rjReader{ + reader := RjReader{ indx: -1, } expected := "bufio: invalid use of UnreadByte" @@ -121,7 +121,7 @@ a/*comment*/b`)) } func TestConsumeComent(t *testing.T) { - rjreader := new(rjReader) + rjreader := new(RjReader) var pkbit byte = '*' expectedErr := "JSON_INCOMPLETE_COMMENT" if _, err := rjreader.consumeComent(pkbit); err == nil || err.Error() != expectedErr { diff --git a/config/rpcconn.go b/config/rpcconn.go index 58d8a9ce7..9d7a991b6 100644 --- a/config/rpcconn.go +++ b/config/rpcconn.go @@ -23,7 +23,7 @@ import ( "github.com/cgrates/rpcclient" ) -// Returns the first cached default value for a RemoteHost connection +// NewDfltRemoteHost returns the first cached default value for a RemoteHost connection func NewDfltRemoteHost() *RemoteHost { if dfltRemoteHost == nil { return new(RemoteHost) // No defaults, most probably we are building the defaults now @@ -32,17 +32,40 @@ func NewDfltRemoteHost() *RemoteHost { return &dfltVal } +// NewDfltRPCConn returns the default value for a RPCConn func NewDfltRPCConn() *RPCConn { return &RPCConn{Strategy: rpcclient.PoolFirst} } +// RPCConns the config for all rpc pools +type RPCConns map[string]*RPCConn + +// AsMapInterface returns the config as a map[string]interface{} +func (rC RPCConns) AsMapInterface() (rpcConns map[string]interface{}) { + rpcConns = make(map[string]interface{}) + for key, value := range rC { + rpcConns[key] = value.AsMapInterface() + } + return +} + +// Clone returns a deep copy of RPCConns +func (rC RPCConns) Clone() (cln RPCConns) { + cln = make(RPCConns) + for id, conn := range rC { + cln[id] = conn.Clone() + } + return +} + +// RPCConn the connection pool config type RPCConn struct { Strategy string PoolSize int Conns []*RemoteHost } -func (rC *RPCConn) loadFromJsonCfg(jsnCfg *RPCConnsJson) { +func (rC *RPCConn) loadFromJSONCfg(jsnCfg *RPCConnsJson) { if jsnCfg == nil { return } @@ -56,22 +79,13 @@ func (rC *RPCConn) loadFromJsonCfg(jsnCfg *RPCConnsJson) { rC.Conns = make([]*RemoteHost, len(*jsnCfg.Conns)) for idx, jsnHaCfg := range *jsnCfg.Conns { rC.Conns[idx] = NewDfltRemoteHost() - rC.Conns[idx].loadFromJsonCfg(jsnHaCfg) //To review if the function signature changes + rC.Conns[idx].loadFromJSONCfg(jsnHaCfg) //To review if the function signature changes } } return } -type RpcConns map[string]*RPCConn - -func (rC RpcConns) AsMapInterface() (rpcConns map[string]interface{}) { - rpcConns = make(map[string]interface{}) - for key, value := range rC { - rpcConns[key] = value.AsMapInterface() - } - return -} - +// AsMapInterface returns the config as a map[string]interface{} func (rC *RPCConn) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.StrategyCfg: rC.Strategy, @@ -87,7 +101,22 @@ func (rC *RPCConn) AsMapInterface() (initialMP map[string]interface{}) { return } -// One connection to Rater +// Clone returns a deep copy of RPCConn +func (rC RPCConn) Clone() (cln *RPCConn) { + cln = &RPCConn{ + Strategy: rC.Strategy, + PoolSize: rC.PoolSize, + } + if rC.Conns != nil { + cln.Conns = make([]*RemoteHost, len(rC.Conns)) + for i, req := range rC.Conns { + cln.Conns[i] = req.Clone() + } + } + return +} + +// RemoteHost connection config type RemoteHost struct { Address string Transport string @@ -95,25 +124,26 @@ type RemoteHost struct { TLS bool } -func (self *RemoteHost) loadFromJsonCfg(jsnCfg *RemoteHostJson) { +func (rh *RemoteHost) loadFromJSONCfg(jsnCfg *RemoteHostJson) { if jsnCfg == nil { return } if jsnCfg.Address != nil { - self.Address = *jsnCfg.Address + rh.Address = *jsnCfg.Address } if jsnCfg.Transport != nil { - self.Transport = *jsnCfg.Transport + rh.Transport = *jsnCfg.Transport } if jsnCfg.Synchronous != nil { - self.Synchronous = *jsnCfg.Synchronous + rh.Synchronous = *jsnCfg.Synchronous } if jsnCfg.Tls != nil { - self.TLS = *jsnCfg.Tls + rh.TLS = *jsnCfg.Tls } return } +// AsMapInterface returns the config as a map[string]interface{} func (rh *RemoteHost) AsMapInterface() map[string]interface{} { return map[string]interface{}{ utils.AddressCfg: rh.Address, @@ -122,3 +152,13 @@ func (rh *RemoteHost) AsMapInterface() map[string]interface{} { utils.TLS: rh.TLS, } } + +// Clone returns a deep copy of RemoteHost +func (rh RemoteHost) Clone() (cln *RemoteHost) { + return &RemoteHost{ + Address: rh.Address, + Transport: rh.Transport, + Synchronous: rh.Synchronous, + TLS: rh.TLS, + } +} diff --git a/config/rpcconn_test.go b/config/rpcconn_test.go index 5a0645c06..027e076ec 100644 --- a/config/rpcconn_test.go +++ b/config/rpcconn_test.go @@ -38,7 +38,7 @@ func TestRPCConnsloadFromJsonCfgCase1(t *testing.T) { }, }, } - expected := RpcConns{ + expected := RPCConns{ utils.MetaInternal: { Strategy: utils.MetaFirst, PoolSize: 0, @@ -67,7 +67,7 @@ func TestRPCConnsloadFromJsonCfgCase1(t *testing.T) { if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) } else { - jsonCfg.rpcConns[utils.MetaLocalHost].loadFromJsonCfg(cfgJSON) + jsonCfg.rpcConns[utils.MetaLocalHost].loadFromJSONCfg(cfgJSON) if !reflect.DeepEqual(jsonCfg.rpcConns, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.rpcConns)) } @@ -75,7 +75,7 @@ func TestRPCConnsloadFromJsonCfgCase1(t *testing.T) { } func TestRPCConnsloadFromJsonCfgCase2(t *testing.T) { - expected := RpcConns{ + expected := RPCConns{ utils.MetaInternal: { Strategy: utils.MetaFirst, PoolSize: 0, @@ -105,7 +105,7 @@ func TestRPCConnsloadFromJsonCfgCase2(t *testing.T) { if err != nil { t.Error(err) } - jsonCfg.rpcConns[utils.MetaLocalHost].loadFromJsonCfg(nil) + jsonCfg.rpcConns[utils.MetaLocalHost].loadFromJSONCfg(nil) if !reflect.DeepEqual(expected, jsonCfg.rpcConns) { t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.rpcConns)) } @@ -195,3 +195,39 @@ func TestRpcConnAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } + +func TestRPCConnsClone(t *testing.T) { + ban := RPCConns{ + utils.MetaInternal: { + Strategy: utils.MetaFirst, + PoolSize: 0, + Conns: []*RemoteHost{ + { + Address: utils.MetaInternal, + Transport: utils.EmptyString, + Synchronous: false, + TLS: false, + }, + }, + }, + utils.MetaLocalHost: { + Strategy: utils.MetaFirst, + PoolSize: 1, + Conns: []*RemoteHost{ + { + Address: "127.0.0.1:2012", + Transport: "*json", + Synchronous: false, + TLS: false, + }, + }, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv[utils.MetaInternal].Conns[0].Address = ""; ban[utils.MetaInternal].Conns[0].Address != utils.MetaInternal { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/schedulercfg.go b/config/schedulercfg.go index 8626c97c2..ee818b878 100644 --- a/config/schedulercfg.go +++ b/config/schedulercfg.go @@ -19,11 +19,10 @@ along with this program. If not, see package config import ( - "strings" - "github.com/cgrates/cgrates/utils" ) +// SchedulerCfg the condig section for scheduler type SchedulerCfg struct { Enabled bool CDRsConns []string @@ -43,10 +42,9 @@ func (schdcfg *SchedulerCfg) loadFromJSONCfg(jsnCfg *SchedulerJsonCfg) error { schdcfg.CDRsConns = make([]string, len(*jsnCfg.Cdrs_conns)) for idx, conn := range *jsnCfg.Cdrs_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + schdcfg.CDRsConns[idx] = conn if conn == utils.MetaInternal { schdcfg.CDRsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) - } else { - schdcfg.CDRsConns[idx] = conn } } } @@ -60,10 +58,9 @@ func (schdcfg *SchedulerCfg) loadFromJSONCfg(jsnCfg *SchedulerJsonCfg) error { schdcfg.ThreshSConns = make([]string, len(*jsnCfg.Thresholds_conns)) for idx, connID := range *jsnCfg.Thresholds_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + schdcfg.ThreshSConns[idx] = connID if connID == utils.MetaInternal { schdcfg.ThreshSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } else { - schdcfg.ThreshSConns[idx] = connID } } } @@ -71,16 +68,16 @@ func (schdcfg *SchedulerCfg) loadFromJSONCfg(jsnCfg *SchedulerJsonCfg) error { schdcfg.StatSConns = make([]string, len(*jsnCfg.Stats_conns)) for idx, connID := range *jsnCfg.Stats_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + schdcfg.StatSConns[idx] = connID if connID == utils.MetaInternal { schdcfg.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats) - } else { - schdcfg.StatSConns[idx] = connID } } } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (schdcfg *SchedulerCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: schdcfg.Enabled, @@ -89,10 +86,9 @@ func (schdcfg *SchedulerCfg) AsMapInterface() (initialMP map[string]interface{}) if schdcfg.CDRsConns != nil { cdrsConns := make([]string, len(schdcfg.CDRsConns)) for i, item := range schdcfg.CDRsConns { + cdrsConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) { - cdrsConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaCDRs) - } else { - cdrsConns[i] = item + cdrsConns[i] = utils.MetaInternal } } initialMP[utils.CDRsConnsCfg] = cdrsConns @@ -100,10 +96,9 @@ func (schdcfg *SchedulerCfg) AsMapInterface() (initialMP map[string]interface{}) if schdcfg.ThreshSConns != nil { thrsConns := make([]string, len(schdcfg.ThreshSConns)) for i, item := range schdcfg.ThreshSConns { + thrsConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { - thrsConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaThresholds) - } else { - thrsConns[i] = item + thrsConns[i] = utils.MetaInternal } } initialMP[utils.ThreshSConnsCfg] = thrsConns @@ -111,13 +106,45 @@ func (schdcfg *SchedulerCfg) AsMapInterface() (initialMP map[string]interface{}) if schdcfg.StatSConns != nil { stsConns := make([]string, len(schdcfg.StatSConns)) for i, item := range schdcfg.StatSConns { + stsConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats) { - stsConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaStats) - } else { - stsConns[i] = item + stsConns[i] = utils.MetaInternal } } initialMP[utils.StatSConnsCfg] = stsConns } return } + +// Clone returns a deep copy of SchedulerCfg +func (schdcfg SchedulerCfg) Clone() (cln *SchedulerCfg) { + cln = &SchedulerCfg{ + Enabled: schdcfg.Enabled, + } + if schdcfg.CDRsConns != nil { + cln.CDRsConns = make([]string, len(schdcfg.CDRsConns)) + for i, con := range schdcfg.CDRsConns { + cln.CDRsConns[i] = con + } + } + if schdcfg.ThreshSConns != nil { + cln.ThreshSConns = make([]string, len(schdcfg.ThreshSConns)) + for i, con := range schdcfg.ThreshSConns { + cln.ThreshSConns[i] = con + } + } + if schdcfg.StatSConns != nil { + cln.StatSConns = make([]string, len(schdcfg.StatSConns)) + for i, con := range schdcfg.StatSConns { + cln.StatSConns[i] = con + } + } + if schdcfg.Filters != nil { + cln.Filters = make([]string, len(schdcfg.Filters)) + for i, con := range schdcfg.Filters { + cln.Filters[i] = con + } + } + + return +} diff --git a/config/schedulercfg_test.go b/config/schedulercfg_test.go index 69788e429..9b6d50afa 100644 --- a/config/schedulercfg_test.go +++ b/config/schedulercfg_test.go @@ -91,3 +91,29 @@ func TestSchedulerCfgAsMapInterface1(t *testing.T) { } } + +func TestSchedulerCfgClone(t *testing.T) { + ban := &SchedulerCfg{ + Enabled: true, + CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs), "*conn1"}, + ThreshSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"}, + StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "*conn1"}, + Filters: []string{"randomFilter"}, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.CDRsConns[1] = ""; ban.CDRsConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ThreshSConns[1] = ""; ban.ThreshSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.StatSConns[1] = ""; ban.StatSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.Filters[0] = ""; ban.Filters[0] != "randomFilter" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/sessionscfg.go b/config/sessionscfg.go index d7dd0126c..e913fd27a 100644 --- a/config/sessionscfg.go +++ b/config/sessionscfg.go @@ -20,13 +20,12 @@ package config import ( "fmt" - "strings" "time" "github.com/cgrates/cgrates/utils" ) -// Returns the first cached default value for a FreeSWITCHAgent connection +// NewDfltFsConnConfig returns the first cached default value for a FreeSWITCHAgent connection func NewDfltFsConnConfig() *FsConnCfg { if dfltFsConnConfig == nil { return new(FsConnCfg) // No defaults, most probably we are building the defaults now @@ -35,7 +34,7 @@ func NewDfltFsConnConfig() *FsConnCfg { return &dfltVal } -// One connection to FreeSWITCH server +// FsConnCfg one connection to FreeSWITCH server type FsConnCfg struct { Address string Password string @@ -43,27 +42,28 @@ type FsConnCfg struct { Alias string } -func (self *FsConnCfg) loadFromJsonCfg(jsnCfg *FsConnJsonCfg) error { +func (fs *FsConnCfg) loadFromJSONCfg(jsnCfg *FsConnJsonCfg) error { if jsnCfg == nil { return nil } if jsnCfg.Address != nil { - self.Address = *jsnCfg.Address + fs.Address = *jsnCfg.Address } if jsnCfg.Password != nil { - self.Password = *jsnCfg.Password + fs.Password = *jsnCfg.Password } if jsnCfg.Reconnects != nil { - self.Reconnects = *jsnCfg.Reconnects + fs.Reconnects = *jsnCfg.Reconnects } - self.Alias = self.Address + fs.Alias = fs.Address if jsnCfg.Alias != nil && *jsnCfg.Alias != "" { - self.Alias = *jsnCfg.Alias + fs.Alias = *jsnCfg.Alias } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (fs *FsConnCfg) AsMapInterface() map[string]interface{} { return map[string]interface{}{ utils.AddressCfg: fs.Address, @@ -73,6 +73,17 @@ func (fs *FsConnCfg) AsMapInterface() map[string]interface{} { } } +// Clone returns a deep copy of AsteriskAgentCfg +func (fs FsConnCfg) Clone() *FsConnCfg { + return &FsConnCfg{ + Address: fs.Address, + Password: fs.Password, + Reconnects: fs.Reconnects, + Alias: fs.Alias, + } +} + +// SessionSCfg is the config section for SessionS type SessionSCfg struct { Enabled bool ListenBijson string @@ -92,7 +103,7 @@ type SessionSCfg struct { SessionTTLLastUsed *time.Duration SessionTTLUsage *time.Duration SessionTTLLastUsage *time.Duration - SessionIndexes utils.StringMap + SessionIndexes utils.StringSet ClientProtocol float64 ChannelSyncInterval time.Duration TerminateAttempts int @@ -102,7 +113,7 @@ type SessionSCfg struct { STIRCfg *STIRcfg } -func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { +func (scfg *SessionSCfg) loadFromJSONCfg(jsnCfg *SessionSJsonCfg) (err error) { if jsnCfg == nil { return nil } @@ -116,10 +127,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.ChargerSConns = make([]string, len(*jsnCfg.Chargers_conns)) for idx, connID := range *jsnCfg.Chargers_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.ChargerSConns[idx] = connID if connID == utils.MetaInternal { scfg.ChargerSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers) - } else { - scfg.ChargerSConns[idx] = connID } } } @@ -127,10 +137,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.RALsConns = make([]string, len(*jsnCfg.Rals_conns)) for idx, connID := range *jsnCfg.Rals_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.RALsConns[idx] = connID if connID == utils.MetaInternal { scfg.RALsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder) - } else { - scfg.RALsConns[idx] = connID } } } @@ -138,10 +147,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.ResSConns = make([]string, len(*jsnCfg.Resources_conns)) for idx, connID := range *jsnCfg.Resources_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.ResSConns[idx] = connID if connID == utils.MetaInternal { scfg.ResSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources) - } else { - scfg.ResSConns[idx] = connID } } } @@ -149,10 +157,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.ThreshSConns = make([]string, len(*jsnCfg.Thresholds_conns)) for idx, connID := range *jsnCfg.Thresholds_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.ThreshSConns[idx] = connID if connID == utils.MetaInternal { scfg.ThreshSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } else { - scfg.ThreshSConns[idx] = connID } } } @@ -160,10 +167,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.StatSConns = make([]string, len(*jsnCfg.Stats_conns)) for idx, connID := range *jsnCfg.Stats_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.StatSConns[idx] = connID if connID == utils.MetaInternal { scfg.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) - } else { - scfg.StatSConns[idx] = connID } } } @@ -171,10 +177,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.RouteSConns = make([]string, len(*jsnCfg.Routes_conns)) for idx, connID := range *jsnCfg.Routes_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.RouteSConns[idx] = connID if connID == utils.MetaInternal { scfg.RouteSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes) - } else { - scfg.RouteSConns[idx] = connID } } } @@ -182,10 +187,9 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.AttrSConns = make([]string, len(*jsnCfg.Attributes_conns)) for idx, connID := range *jsnCfg.Attributes_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.AttrSConns[idx] = connID if connID == utils.MetaInternal { scfg.AttrSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) - } else { - scfg.AttrSConns[idx] = connID } } } @@ -193,17 +197,15 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.CDRsConns = make([]string, len(*jsnCfg.Cdrs_conns)) for idx, connID := range *jsnCfg.Cdrs_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.CDRsConns[idx] = connID if connID == utils.MetaInternal { scfg.CDRsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) - } else { - scfg.CDRsConns[idx] = connID } } } if jsnCfg.Replication_conns != nil { scfg.ReplicationConns = make([]string, len(*jsnCfg.Replication_conns)) for idx, connID := range *jsnCfg.Replication_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem if connID == utils.MetaInternal { return fmt.Errorf("Replication connection ID needs to be different than *internal") } @@ -224,35 +226,35 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { } } if jsnCfg.Session_ttl_max_delay != nil { - if maxTTLDelay, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_max_delay); err != nil { + var maxTTLDelay time.Duration + if maxTTLDelay, err = utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_max_delay); err != nil { return err - } else { - scfg.SessionTTLMaxDelay = &maxTTLDelay } + scfg.SessionTTLMaxDelay = &maxTTLDelay } if jsnCfg.Session_ttl_last_used != nil { - if sessionTTLLastUsed, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_last_used); err != nil { + var sessionTTLLastUsed time.Duration + if sessionTTLLastUsed, err = utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_last_used); err != nil { return err - } else { - scfg.SessionTTLLastUsed = &sessionTTLLastUsed } + scfg.SessionTTLLastUsed = &sessionTTLLastUsed } if jsnCfg.Session_ttl_usage != nil { - if sessionTTLUsage, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_usage); err != nil { + var sessionTTLUsage time.Duration + if sessionTTLUsage, err = utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_usage); err != nil { return err - } else { - scfg.SessionTTLUsage = &sessionTTLUsage } + scfg.SessionTTLUsage = &sessionTTLUsage } if jsnCfg.Session_ttl_last_usage != nil { - if sessionTTLLastUsage, err := utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_last_usage); err != nil { + var sessionTTLLastUsage time.Duration + if sessionTTLLastUsage, err = utils.ParseDurationWithNanosecs(*jsnCfg.Session_ttl_last_usage); err != nil { return err - } else { - scfg.SessionTTLLastUsage = &sessionTTLLastUsage } + scfg.SessionTTLLastUsage = &sessionTTLLastUsage } if jsnCfg.Session_indexes != nil { - scfg.SessionIndexes = utils.StringMapFromSlice(*jsnCfg.Session_indexes) + scfg.SessionIndexes = utils.NewStringSet(*jsnCfg.Session_indexes) } if jsnCfg.Client_protocol != nil { scfg.ClientProtocol = *jsnCfg.Client_protocol @@ -277,38 +279,37 @@ func (scfg *SessionSCfg) loadFromJsonCfg(jsnCfg *SessionSJsonCfg) (err error) { scfg.SchedulerConns = make([]string, len(*jsnCfg.Scheduler_conns)) for idx, connID := range *jsnCfg.Scheduler_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + scfg.SchedulerConns[idx] = connID if connID == utils.MetaInternal { scfg.SchedulerConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler) - } else { - scfg.SchedulerConns[idx] = connID } } } return scfg.STIRCfg.loadFromJSONCfg(jsnCfg.Stir) } +// AsMapInterface returns the config as a map[string]interface{} func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.EnabledCfg: scfg.Enabled, - utils.ListenBijsonCfg: scfg.ListenBijson, - utils.ReplicationConnsCfg: scfg.ReplicationConns, - utils.StoreSCostsCfg: scfg.StoreSCosts, - utils.SessionIndexesCfg: scfg.SessionIndexes.Slice(), - utils.ClientProtocolCfg: scfg.ClientProtocol, - utils.TerminateAttemptsCfg: scfg.TerminateAttempts, - utils.AlterableFieldsCfg: scfg.AlterableFields.AsSlice(), - utils.STIRCfg: scfg.STIRCfg.AsMapInterface(), - utils.MinDurLowBalanceCfg: "0", + utils.EnabledCfg: scfg.Enabled, + utils.ListenBijsonCfg: scfg.ListenBijson, + utils.ReplicationConnsCfg: scfg.ReplicationConns, + utils.StoreSCostsCfg: scfg.StoreSCosts, + utils.SessionIndexesCfg: scfg.SessionIndexes.AsSlice(), + utils.ClientProtocolCfg: scfg.ClientProtocol, + utils.TerminateAttemptsCfg: scfg.TerminateAttempts, + utils.AlterableFieldsCfg: scfg.AlterableFields.AsSlice(), + utils.STIRCfg: scfg.STIRCfg.AsMapInterface(), + utils.MinDurLowBalanceCfg: "0", + utils.ChannelSyncIntervalCfg: "0", + utils.DebitIntervalCfg: "0", + utils.SessionTTLCfg: "0", } if scfg.DebitInterval != 0 { initialMP[utils.DebitIntervalCfg] = scfg.DebitInterval.String() - } else if scfg.DebitInterval == 0 { - initialMP[utils.DebitIntervalCfg] = "0" } if scfg.SessionTTL != 0 { initialMP[utils.SessionTTLCfg] = scfg.SessionTTL.String() - } else if scfg.SessionTTL == 0 { - initialMP[utils.SessionTTLCfg] = "0" } if scfg.SessionTTLMaxDelay != nil { initialMP[utils.SessionTTLMaxDelayCfg] = scfg.SessionTTLMaxDelay.String() @@ -324,8 +325,6 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { } if scfg.ChannelSyncInterval != 0 { initialMP[utils.ChannelSyncIntervalCfg] = scfg.ChannelSyncInterval.String() - } else if scfg.ChannelSyncInterval == 0 { - initialMP[utils.ChannelSyncIntervalCfg] = "0" } if scfg.MinDurLowBalance != 0 { initialMP[utils.MinDurLowBalanceCfg] = scfg.MinDurLowBalance.String() @@ -333,10 +332,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.ChargerSConns != nil { chargerSConns := make([]string, len(scfg.ChargerSConns)) for i, item := range scfg.ChargerSConns { + chargerSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers) { - chargerSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaChargers) - } else { - chargerSConns[i] = item + chargerSConns[i] = utils.MetaInternal } } initialMP[utils.ChargerSConnsCfg] = chargerSConns @@ -344,10 +342,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.RALsConns != nil { RALsConns := make([]string, len(scfg.RALsConns)) for i, item := range scfg.RALsConns { + RALsConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder) { - RALsConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaResponder) - } else { - RALsConns[i] = item + RALsConns[i] = utils.MetaInternal } } initialMP[utils.RALsConnsCfg] = RALsConns @@ -355,11 +352,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.ResSConns != nil { resSConns := make([]string, len(scfg.ResSConns)) for i, item := range scfg.ResSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources) - if item == buf { - resSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaResources) - } else { - resSConns[i] = item + resSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources) { + resSConns[i] = utils.MetaInternal } } initialMP[utils.ResourceSConnsCfg] = resSConns @@ -367,11 +362,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.ThreshSConns != nil { threshSConns := make([]string, len(scfg.ThreshSConns)) for i, item := range scfg.ThreshSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - if item == buf { - threshSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaThresholds) - } else { - threshSConns[i] = item + threshSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { + threshSConns[i] = utils.MetaInternal } } initialMP[utils.ThresholdSConnsCfg] = threshSConns @@ -379,11 +372,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.StatSConns != nil { statSConns := make([]string, len(scfg.StatSConns)) for i, item := range scfg.StatSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) - if item == buf { - statSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaStatS) - } else { - statSConns[i] = item + statSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS) { + statSConns[i] = utils.MetaInternal } } initialMP[utils.StatSConnsCfg] = statSConns @@ -391,11 +382,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.RouteSConns != nil { routesConns := make([]string, len(scfg.RouteSConns)) for i, item := range scfg.RouteSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes) - if item == buf { - routesConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaRoutes) - } else { - routesConns[i] = item + routesConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes) { + routesConns[i] = utils.MetaInternal } } initialMP[utils.RouteSConnsCfg] = routesConns @@ -403,11 +392,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.AttrSConns != nil { attrSConns := make([]string, len(scfg.AttrSConns)) for i, item := range scfg.AttrSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) - if item == buf { - attrSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaAttributes) - } else { - attrSConns[i] = item + attrSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) { + attrSConns[i] = utils.MetaInternal } } initialMP[utils.AttributeSConnsCfg] = attrSConns @@ -415,11 +402,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.CDRsConns != nil { CDRsConns := make([]string, len(scfg.CDRsConns)) for i, item := range scfg.CDRsConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) - if item == buf { - CDRsConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaCDRs) - } else { - CDRsConns[i] = item + CDRsConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) { + CDRsConns[i] = utils.MetaInternal } } initialMP[utils.CDRsConnsCfg] = CDRsConns @@ -427,11 +412,9 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { if scfg.SchedulerConns != nil { schedulerConns := make([]string, len(scfg.SchedulerConns)) for i, item := range scfg.SchedulerConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler) - if item == buf { - schedulerConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaScheduler) - } else { - schedulerConns[i] = item + schedulerConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler) { + schedulerConns[i] = utils.MetaInternal } } initialMP[utils.SchedulerConnsCfg] = schedulerConns @@ -439,6 +422,101 @@ func (scfg *SessionSCfg) AsMapInterface() (initialMP map[string]interface{}) { return } +// Clone returns a deep copy of SessionSCfg +func (scfg SessionSCfg) Clone() (cln *SessionSCfg) { + cln = &SessionSCfg{ + Enabled: scfg.Enabled, + ListenBijson: scfg.ListenBijson, + DebitInterval: scfg.DebitInterval, + StoreSCosts: scfg.StoreSCosts, + SessionTTL: scfg.SessionTTL, + ClientProtocol: scfg.ClientProtocol, + ChannelSyncInterval: scfg.ChannelSyncInterval, + TerminateAttempts: scfg.TerminateAttempts, + MinDurLowBalance: scfg.MinDurLowBalance, + + SessionIndexes: scfg.SessionIndexes.Clone(), + AlterableFields: scfg.AlterableFields.Clone(), + STIRCfg: scfg.STIRCfg.Clone(), + } + if scfg.SessionTTLMaxDelay != nil { + cln.SessionTTLMaxDelay = utils.DurationPointer(*scfg.SessionTTLMaxDelay) + } + if scfg.SessionTTLLastUsed != nil { + cln.SessionTTLLastUsed = utils.DurationPointer(*scfg.SessionTTLLastUsed) + } + if scfg.SessionTTLUsage != nil { + cln.SessionTTLUsage = utils.DurationPointer(*scfg.SessionTTLUsage) + } + if scfg.SessionTTLLastUsage != nil { + cln.SessionTTLLastUsage = utils.DurationPointer(*scfg.SessionTTLLastUsage) + } + + if scfg.ChargerSConns != nil { + cln.ChargerSConns = make([]string, len(scfg.ChargerSConns)) + for i, con := range scfg.ChargerSConns { + cln.ChargerSConns[i] = con + } + } + if scfg.RALsConns != nil { + cln.RALsConns = make([]string, len(scfg.RALsConns)) + for i, con := range scfg.RALsConns { + cln.RALsConns[i] = con + } + } + if scfg.ResSConns != nil { + cln.ResSConns = make([]string, len(scfg.ResSConns)) + for i, con := range scfg.ResSConns { + cln.ResSConns[i] = con + } + } + if scfg.ThreshSConns != nil { + cln.ThreshSConns = make([]string, len(scfg.ThreshSConns)) + for i, con := range scfg.ThreshSConns { + cln.ThreshSConns[i] = con + } + } + if scfg.StatSConns != nil { + cln.StatSConns = make([]string, len(scfg.StatSConns)) + for i, con := range scfg.StatSConns { + cln.StatSConns[i] = con + } + } + if scfg.RouteSConns != nil { + cln.RouteSConns = make([]string, len(scfg.RouteSConns)) + for i, con := range scfg.RouteSConns { + cln.RouteSConns[i] = con + } + } + if scfg.AttrSConns != nil { + cln.AttrSConns = make([]string, len(scfg.AttrSConns)) + for i, con := range scfg.AttrSConns { + cln.AttrSConns[i] = con + } + } + if scfg.CDRsConns != nil { + cln.CDRsConns = make([]string, len(scfg.CDRsConns)) + for i, con := range scfg.CDRsConns { + cln.CDRsConns[i] = con + } + } + if scfg.ReplicationConns != nil { + cln.ReplicationConns = make([]string, len(scfg.ReplicationConns)) + for i, con := range scfg.ReplicationConns { + cln.ReplicationConns[i] = con + } + } + if scfg.SchedulerConns != nil { + cln.SchedulerConns = make([]string, len(scfg.SchedulerConns)) + for i, con := range scfg.SchedulerConns { + cln.SchedulerConns[i] = con + } + } + + return +} + +// FsAgentCfg the config section that describes the FreeSWITCH Agent type FsAgentCfg struct { Enabled bool SessionSConns []string @@ -452,7 +530,7 @@ type FsAgentCfg struct { EventSocketConns []*FsConnCfg } -func (fscfg *FsAgentCfg) loadFromJsonCfg(jsnCfg *FreeswitchAgentJsonCfg) error { +func (fscfg *FsAgentCfg) loadFromJSONCfg(jsnCfg *FreeswitchAgentJsonCfg) error { if jsnCfg == nil { return nil } @@ -464,10 +542,9 @@ func (fscfg *FsAgentCfg) loadFromJsonCfg(jsnCfg *FreeswitchAgentJsonCfg) error { fscfg.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, connID := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + fscfg.SessionSConns[idx] = connID if connID == utils.MetaInternal { fscfg.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - } else { - fscfg.SessionSConns[idx] = connID } } } @@ -501,12 +578,13 @@ func (fscfg *FsAgentCfg) loadFromJsonCfg(jsnCfg *FreeswitchAgentJsonCfg) error { fscfg.EventSocketConns = make([]*FsConnCfg, len(*jsnCfg.Event_socket_conns)) for idx, jsnConnCfg := range *jsnCfg.Event_socket_conns { fscfg.EventSocketConns[idx] = NewDfltFsConnConfig() - fscfg.EventSocketConns[idx].loadFromJsonCfg(jsnConnCfg) + fscfg.EventSocketConns[idx].loadFromJSONCfg(jsnConnCfg) } } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (fscfg *FsAgentCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: fscfg.Enabled, @@ -519,21 +597,15 @@ func (fscfg *FsAgentCfg) AsMapInterface(separator string) (initialMP map[string] if fscfg.SessionSConns != nil { sessionSConns := make([]string, len(fscfg.SessionSConns)) for i, item := range fscfg.SessionSConns { - buf := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - if item == buf { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + sessionSConns[i] = item + if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns } if fscfg.ExtraFields != nil { - values := make([]string, len(fscfg.ExtraFields)) - for i, item := range fscfg.ExtraFields { - values[i] = item.Rules - } - initialMP[utils.ExtraFieldsCfg] = strings.Join(values, separator) + initialMP[utils.ExtraFieldsCfg] = fscfg.ExtraFields.GetRule(separator) } if fscfg.MaxWaitConnection != 0 { @@ -551,16 +623,34 @@ func (fscfg *FsAgentCfg) AsMapInterface(separator string) (initialMP map[string] return } -// Returns the first cached default value for a FreeSWITCHAgent connection -func NewDfltKamConnConfig() *KamConnCfg { - if dfltKamConnConfig == nil { - return new(KamConnCfg) // No defaults, most probably we are building the defaults now +// Clone returns a deep copy of FsAgentCfg +func (fscfg FsAgentCfg) Clone() (cln *FsAgentCfg) { + cln = &FsAgentCfg{ + Enabled: fscfg.Enabled, + SubscribePark: fscfg.SubscribePark, + CreateCdr: fscfg.CreateCdr, + ExtraFields: fscfg.ExtraFields.Clone(), + LowBalanceAnnFile: fscfg.LowBalanceAnnFile, + EmptyBalanceContext: fscfg.EmptyBalanceContext, + EmptyBalanceAnnFile: fscfg.EmptyBalanceAnnFile, + MaxWaitConnection: fscfg.MaxWaitConnection, } - dfltVal := *dfltKamConnConfig - return &dfltVal + if fscfg.SessionSConns != nil { + cln.SessionSConns = make([]string, len(fscfg.SessionSConns)) + for i, con := range fscfg.SessionSConns { + cln.SessionSConns[i] = con + } + } + if fscfg.EventSocketConns != nil { + cln.EventSocketConns = make([]*FsConnCfg, len(fscfg.EventSocketConns)) + for i, req := range fscfg.EventSocketConns { + cln.EventSocketConns[i] = req.Clone() + } + } + return } -// Uses stored defaults so we can pre-populate by loading from JSON config +// NewDefaultAsteriskConnCfg is uses stored defaults so we can pre-populate by loading from JSON config func NewDefaultAsteriskConnCfg() *AsteriskConnCfg { if dfltAstConnCfg == nil { return new(AsteriskConnCfg) // No defaults, most probably we are building the defaults now @@ -569,6 +659,7 @@ func NewDefaultAsteriskConnCfg() *AsteriskConnCfg { return &dfltVal } +// AsteriskConnCfg the config for a Asterisk connection type AsteriskConnCfg struct { Alias string Address string @@ -578,7 +669,7 @@ type AsteriskConnCfg struct { Reconnects int } -func (aConnCfg *AsteriskConnCfg) loadFromJsonCfg(jsnCfg *AstConnJsonCfg) error { +func (aConnCfg *AsteriskConnCfg) loadFromJSONCfg(jsnCfg *AstConnJsonCfg) error { if jsnCfg == nil { return nil } @@ -603,6 +694,7 @@ func (aConnCfg *AsteriskConnCfg) loadFromJsonCfg(jsnCfg *AstConnJsonCfg) error { return nil } +// AsMapInterface returns the config as a map[string]interface{} func (aConnCfg *AsteriskConnCfg) AsMapInterface() map[string]interface{} { return map[string]interface{}{ utils.AliasCfg: aConnCfg.Alias, @@ -614,6 +706,19 @@ func (aConnCfg *AsteriskConnCfg) AsMapInterface() map[string]interface{} { } } +// Clone returns a deep copy of AsteriskConnCfg +func (aConnCfg AsteriskConnCfg) Clone() *AsteriskConnCfg { + return &AsteriskConnCfg{ + Alias: aConnCfg.Alias, + Address: aConnCfg.Address, + User: aConnCfg.User, + Password: aConnCfg.Password, + ConnectAttempts: aConnCfg.ConnectAttempts, + Reconnects: aConnCfg.Reconnects, + } +} + +// AsteriskAgentCfg the config section that describes the Asterisk Agent type AsteriskAgentCfg struct { Enabled bool SessionSConns []string @@ -621,7 +726,7 @@ type AsteriskAgentCfg struct { AsteriskConns []*AsteriskConnCfg } -func (aCfg *AsteriskAgentCfg) loadFromJsonCfg(jsnCfg *AsteriskAgentJsonCfg) (err error) { +func (aCfg *AsteriskAgentCfg) loadFromJSONCfg(jsnCfg *AsteriskAgentJsonCfg) (err error) { if jsnCfg == nil { return nil } @@ -632,10 +737,9 @@ func (aCfg *AsteriskAgentCfg) loadFromJsonCfg(jsnCfg *AsteriskAgentJsonCfg) (err aCfg.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) for idx, attrConn := range *jsnCfg.Sessions_conns { // if we have the connection internal we change the name so we can have internal rpc for each subsystem + aCfg.SessionSConns[idx] = attrConn if attrConn == utils.MetaInternal { aCfg.SessionSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) - } else { - aCfg.SessionSConns[idx] = attrConn } } } @@ -647,12 +751,13 @@ func (aCfg *AsteriskAgentCfg) loadFromJsonCfg(jsnCfg *AsteriskAgentJsonCfg) (err aCfg.AsteriskConns = make([]*AsteriskConnCfg, len(*jsnCfg.Asterisk_conns)) for i, jsnAConn := range *jsnCfg.Asterisk_conns { aCfg.AsteriskConns[i] = NewDefaultAsteriskConnCfg() - aCfg.AsteriskConns[i].loadFromJsonCfg(jsnAConn) + aCfg.AsteriskConns[i].loadFromJSONCfg(jsnAConn) } } return nil } +// AsMapInterface returns the config as a map[string]interface{} func (aCfg *AsteriskAgentCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: aCfg.Enabled, @@ -668,10 +773,9 @@ func (aCfg *AsteriskAgentCfg) AsMapInterface() (initialMP map[string]interface{} if aCfg.SessionSConns != nil { sessionSConns := make([]string, len(aCfg.SessionSConns)) for i, item := range aCfg.SessionSConns { + sessionSConns[i] = item if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = strings.TrimSuffix(item, utils.CONCATENATED_KEY_SEP+utils.MetaSessionS) - } else { - sessionSConns[i] = item + sessionSConns[i] = utils.MetaInternal } } initialMP[utils.SessionSConnsCfg] = sessionSConns @@ -679,6 +783,27 @@ func (aCfg *AsteriskAgentCfg) AsMapInterface() (initialMP map[string]interface{} return } +// Clone returns a deep copy of AsteriskAgentCfg +func (aCfg AsteriskAgentCfg) Clone() (cln *AsteriskAgentCfg) { + cln = &AsteriskAgentCfg{ + Enabled: aCfg.Enabled, + CreateCDR: aCfg.CreateCDR, + } + if aCfg.SessionSConns != nil { + cln.SessionSConns = make([]string, len(aCfg.SessionSConns)) + for i, con := range aCfg.SessionSConns { + cln.SessionSConns[i] = con + } + } + if aCfg.AsteriskConns != nil { + cln.AsteriskConns = make([]*AsteriskConnCfg, len(aCfg.AsteriskConns)) + for i, req := range aCfg.AsteriskConns { + cln.AsteriskConns[i] = req.Clone() + } + } + return +} + // STIRcfg the confuguration structure for STIR type STIRcfg struct { AllowedAttest utils.StringSet @@ -712,21 +837,30 @@ func (stirCfg *STIRcfg) loadFromJSONCfg(jsnCfg *STIRJsonCfg) (err error) { return nil } +// AsMapInterface returns the config as a map[string]interface{} func (stirCfg *STIRcfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ - utils.DefaultAttestCfg: stirCfg.DefaultAttest, - utils.PublicKeyPathCfg: stirCfg.PublicKeyPath, - utils.PrivateKeyPathCfg: stirCfg.PrivateKeyPath, - utils.AllowedAtestCfg: stirCfg.AllowedAttest.AsSlice(), + utils.DefaultAttestCfg: stirCfg.DefaultAttest, + utils.PublicKeyPathCfg: stirCfg.PublicKeyPath, + utils.PrivateKeyPathCfg: stirCfg.PrivateKeyPath, + utils.AllowedAtestCfg: stirCfg.AllowedAttest.AsSlice(), + utils.PayloadMaxdurationCfg: "0", } - var payloadMaxduration string if stirCfg.PayloadMaxduration > 0 { - payloadMaxduration = stirCfg.PayloadMaxduration.String() - } else if stirCfg.PayloadMaxduration == 0 { - payloadMaxduration = "0" - } else { - payloadMaxduration = "-1" + initialMP[utils.PayloadMaxdurationCfg] = stirCfg.PayloadMaxduration.String() + } else if stirCfg.PayloadMaxduration < 0 { + initialMP[utils.PayloadMaxdurationCfg] = "-1" } - initialMP[utils.PayloadMaxdurationCfg] = payloadMaxduration return } + +// Clone returns a deep copy of STIRcfg +func (stirCfg STIRcfg) Clone() *STIRcfg { + return &STIRcfg{ + AllowedAttest: stirCfg.AllowedAttest.Clone(), + PayloadMaxduration: stirCfg.PayloadMaxduration, + DefaultAttest: stirCfg.DefaultAttest, + PublicKeyPath: stirCfg.PublicKeyPath, + PrivateKeyPath: stirCfg.PrivateKeyPath, + } +} diff --git a/config/sessionscfg_test.go b/config/sessionscfg_test.go index 8999b8823..45cf69916 100644 --- a/config/sessionscfg_test.go +++ b/config/sessionscfg_test.go @@ -21,6 +21,7 @@ import ( "reflect" "sort" "testing" + "time" "github.com/cgrates/cgrates/utils" ) @@ -53,7 +54,7 @@ func TestFsAgentCfgloadFromJsonCfg1(t *testing.T) { }, } fsAgentCfg := new(FsAgentCfg) - if err := fsAgentCfg.loadFromJsonCfg(fsAgentJsnCfg); err != nil { + if err := fsAgentCfg.loadFromJSONCfg(fsAgentJsnCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(eFsAgentConfig, fsAgentCfg) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(eFsAgentConfig), utils.ToJSON(fsAgentCfg)) @@ -106,7 +107,7 @@ func TestSessionSCfgloadFromJsonCfgCase1(t *testing.T) { DebitInterval: 2, StoreSCosts: true, SessionTTL: 0, - SessionIndexes: utils.StringMap{}, + SessionIndexes: utils.StringSet{}, ClientProtocol: 2.5, ChannelSyncInterval: 10, TerminateAttempts: 6, @@ -123,7 +124,7 @@ func TestSessionSCfgloadFromJsonCfgCase1(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsonCfg.sessionSCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.sessionSCfg)) @@ -137,7 +138,7 @@ func TestSessionSCfgloadFromJsonCfgCase2(t *testing.T) { expected := "Replication connection ID needs to be different than *internal" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -149,7 +150,7 @@ func TestSessionSCfgloadFromJsonCfgCase3(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -161,7 +162,7 @@ func TestSessionSCfgloadFromJsonCfgCase5(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -173,7 +174,7 @@ func TestSessionSCfgloadFromJsonCfgCase7(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -185,7 +186,7 @@ func TestSessionSCfgloadFromJsonCfgCase8(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -197,7 +198,7 @@ func TestSessionSCfgloadFromJsonCfgCase9(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } cfgJSON1 := &SessionSJsonCfg{ @@ -205,7 +206,7 @@ func TestSessionSCfgloadFromJsonCfgCase9(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON1); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON1); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } cfgJSON2 := &SessionSJsonCfg{ @@ -213,7 +214,7 @@ func TestSessionSCfgloadFromJsonCfgCase9(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON2); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON2); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } cfgJSON3 := &SessionSJsonCfg{ @@ -221,7 +222,7 @@ func TestSessionSCfgloadFromJsonCfgCase9(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON3); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON3); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -248,7 +249,7 @@ func TestSessionSCfgloadFromJsonCfgCase10(t *testing.T) { DebitInterval: 0, StoreSCosts: false, SessionTTL: 0, - SessionIndexes: utils.StringMap{}, + SessionIndexes: utils.StringSet{}, ClientProtocol: 1.0, ChannelSyncInterval: 0, TerminateAttempts: 5, @@ -269,7 +270,7 @@ func TestSessionSCfgloadFromJsonCfgCase10(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(jsonCfg.sessionSCfg, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.sessionSCfg)) @@ -285,7 +286,7 @@ func TestSessionSCfgloadFromJsonCfgCase11(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.sessionSCfg.loadFromJsonCfg(cfgJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.sessionSCfg.loadFromJSONCfg(cfgJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -483,7 +484,7 @@ func TestFsAgentCfgloadFromJsonCfgCase1(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.fsAgentCfg.loadFromJsonCfg(fsAgentJsnCfg); err != nil { + } else if err = jsonCfg.fsAgentCfg.loadFromJSONCfg(fsAgentJsnCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsonCfg.fsAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.fsAgentCfg)) @@ -497,7 +498,7 @@ func TestFsAgentCfgloadFromJsonCfgCase2(t *testing.T) { expected := "time: unknown unit \"ss\" in duration \"1ss\"" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.fsAgentCfg.loadFromJsonCfg(fsAgentJsnCfg); err == nil || err.Error() != expected { + } else if err = jsonCfg.fsAgentCfg.loadFromJSONCfg(fsAgentJsnCfg); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -509,7 +510,7 @@ func TestFsAgentCfgloadFromJsonCfgCase3(t *testing.T) { expected := "invalid converter terminator in rule: " if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.fsAgentCfg.loadFromJsonCfg(fsAgentJsnCfg); err == nil || err.Error() != expected { + } else if err = jsonCfg.fsAgentCfg.loadFromJSONCfg(fsAgentJsnCfg); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", expected, err) } } @@ -603,12 +604,12 @@ func TestFsAgentCfgAsMapInterfaceCase3(t *testing.T) { func TestFsConnCfgloadFromJsonCfg(t *testing.T) { var fscocfg, expected FsConnCfg - if err := fscocfg.loadFromJsonCfg(nil); err != nil { + if err := fscocfg.loadFromJSONCfg(nil); err != nil { t.Error(err) } else if !reflect.DeepEqual(fscocfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, fscocfg) } - if err := fscocfg.loadFromJsonCfg(new(FsConnJsonCfg)); err != nil { + if err := fscocfg.loadFromJSONCfg(new(FsConnJsonCfg)); err != nil { t.Error(err) } else if !reflect.DeepEqual(fscocfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, fscocfg) @@ -625,7 +626,7 @@ func TestFsConnCfgloadFromJsonCfg(t *testing.T) { Reconnects: 5, Alias: "127.0.0.1:8448", } - if err = fscocfg.loadFromJsonCfg(json); err != nil { + if err = fscocfg.loadFromJSONCfg(json); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, fscocfg) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(expected), utils.ToJSON(fscocfg)) @@ -634,11 +635,11 @@ func TestFsConnCfgloadFromJsonCfg(t *testing.T) { func TestRemoteHostloadFromJsonCfg(t *testing.T) { var hpoolcfg, expected RemoteHost - hpoolcfg.loadFromJsonCfg(nil) + hpoolcfg.loadFromJSONCfg(nil) if !reflect.DeepEqual(hpoolcfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, hpoolcfg) } - hpoolcfg.loadFromJsonCfg(new(RemoteHostJson)) + hpoolcfg.loadFromJSONCfg(new(RemoteHostJson)) if !reflect.DeepEqual(hpoolcfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, hpoolcfg) } @@ -650,7 +651,7 @@ func TestRemoteHostloadFromJsonCfg(t *testing.T) { Address: "127.0.0.1:8448", Synchronous: true, } - hpoolcfg.loadFromJsonCfg(json) + hpoolcfg.loadFromJSONCfg(json) if !reflect.DeepEqual(expected, hpoolcfg) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(expected), utils.ToJSON(hpoolcfg)) } @@ -687,7 +688,7 @@ func TestAsteriskAgentCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.asteriskAgentCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsonCfg.asteriskAgentCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsonCfg.asteriskAgentCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.asteriskAgentCfg)) @@ -741,12 +742,12 @@ func TestAsteriskAgentCfgAsMapInterface1(t *testing.T) { func TestAsteriskConnCfgloadFromJsonCfg(t *testing.T) { var asconcfg, expected AsteriskConnCfg - if err := asconcfg.loadFromJsonCfg(nil); err != nil { + if err := asconcfg.loadFromJSONCfg(nil); err != nil { t.Error(err) } else if !reflect.DeepEqual(asconcfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, asconcfg) } - if err := asconcfg.loadFromJsonCfg(new(AstConnJsonCfg)); err != nil { + if err := asconcfg.loadFromJSONCfg(new(AstConnJsonCfg)); err != nil { t.Error(err) } else if !reflect.DeepEqual(asconcfg, expected) { t.Errorf("Expected: %+v ,received: %+v", expected, asconcfg) @@ -765,9 +766,136 @@ func TestAsteriskConnCfgloadFromJsonCfg(t *testing.T) { ConnectAttempts: 3, Reconnects: 5, } - if err = asconcfg.loadFromJsonCfg(json); err != nil { + if err = asconcfg.loadFromJSONCfg(json); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, asconcfg) { t.Errorf("Expected: %+v , received: %+v", utils.ToJSON(expected), utils.ToJSON(asconcfg)) } } + +func TestAsteriskAgentCfgClone(t *testing.T) { + ban := &AsteriskAgentCfg{ + Enabled: true, + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + CreateCDR: true, + AsteriskConns: []*AsteriskConnCfg{{ + Alias: "127.0.0.1:8448", + Address: "127.0.0.1:8088", + User: "cgrates", + Password: "CGRateS.org", + ConnectAttempts: 3, + Reconnects: 5, + }}, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.AsteriskConns[0].User = ""; ban.AsteriskConns[0].User != "cgrates" { + t.Errorf("Expected clone to not modify the cloned") + } +} + +func TestFsAgentCfgClone(t *testing.T) { + ban := &FsAgentCfg{ + Enabled: true, + CreateCdr: true, + SubscribePark: true, + EmptyBalanceAnnFile: "file", + EmptyBalanceContext: "context", + ExtraFields: NewRSRParsersMustCompile("tenant", utils.INFIELD_SEP), + LowBalanceAnnFile: "file2", + MaxWaitConnection: time.Second, + SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, + EventSocketConns: []*FsConnCfg{ + {Address: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5, Alias: "1.2.3.4:8021"}, + {Address: "2.3.4.5:8021", Password: "ClueCon", Reconnects: 5, Alias: "2.3.4.5:8021"}, + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.SessionSConns[1] = ""; ban.SessionSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.EventSocketConns[0].Password = ""; ban.EventSocketConns[0].Password != "ClueCon" { + t.Errorf("Expected clone to not modify the cloned") + } +} + +func TestSessionSCfgClone(t *testing.T) { + ban := &SessionSCfg{ + Enabled: true, + ListenBijson: "127.0.0.1:2018", + ChargerSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers), "*conn1"}, + RALsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder), "*conn1"}, + ResSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources), "*conn1"}, + ThreshSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"}, + StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS), "*conn1"}, + RouteSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes), "*conn1"}, + AttrSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes), "*conn1"}, + CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs), "*conn1"}, + ReplicationConns: []string{"*conn1"}, + DebitInterval: 2, + StoreSCosts: true, + SessionTTL: 0, + SessionIndexes: utils.StringSet{}, + ClientProtocol: 2.5, + ChannelSyncInterval: 10, + TerminateAttempts: 6, + AlterableFields: utils.StringSet{}, + MinDurLowBalance: 1, + SchedulerConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler), "*conn1"}, + SessionTTLMaxDelay: utils.DurationPointer(time.Second), + SessionTTLLastUsed: utils.DurationPointer(time.Second), + SessionTTLUsage: utils.DurationPointer(time.Second), + SessionTTLLastUsage: utils.DurationPointer(time.Second), + STIRCfg: &STIRcfg{ + AllowedAttest: utils.StringSet{utils.META_ANY: {}}, + PayloadMaxduration: -1, + DefaultAttest: "A", + PrivateKeyPath: "randomPath", + PublicKeyPath: "randomPath", + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.ChargerSConns[1] = ""; ban.ChargerSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + + if rcv.RALsConns[1] = ""; ban.RALsConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ResSConns[1] = ""; ban.ResSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ThreshSConns[1] = ""; ban.ThreshSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.StatSConns[1] = ""; ban.StatSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RouteSConns[1] = ""; ban.RouteSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.AttrSConns[1] = ""; ban.AttrSConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.CDRsConns[1] = ""; ban.CDRsConns[1] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.ReplicationConns[0] = ""; ban.ReplicationConns[0] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + + if rcv.STIRCfg.DefaultAttest = ""; ban.STIRCfg.DefaultAttest != "A" { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/config/stordbcfg.go b/config/stordbcfg.go index babad649d..da6f35e1a 100644 --- a/config/stordbcfg.go +++ b/config/stordbcfg.go @@ -42,8 +42,8 @@ type StorDbCfg struct { Opts map[string]interface{} } -// loadFromJsonCfg loads StoreDb config from JsonCfg -func (dbcfg *StorDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { +// loadFromJSONCfg loads StoreDb config from JsonCfg +func (dbcfg *StorDbCfg) loadFromJSONCfg(jsnDbCfg *DbJsonCfg) (err error) { if jsnDbCfg == nil { return nil } @@ -101,7 +101,7 @@ func (dbcfg *StorDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { if jsnDbCfg.Items != nil { for kJsn, vJsn := range *jsnDbCfg.Items { val := new(ItemOpt) - val.loadFromJsonCfg(vJsn) //To review if the function signature changes + val.loadFromJSONCfg(vJsn) //To review if the function signature changes dbcfg.Items[kJsn] = val } } @@ -109,27 +109,52 @@ func (dbcfg *StorDbCfg) loadFromJsonCfg(jsnDbCfg *DbJsonCfg) (err error) { } // Clone returns the cloned object -func (dbcfg *StorDbCfg) Clone() *StorDbCfg { - items := make(map[string]*ItemOpt) +func (dbcfg *StorDbCfg) Clone() (cln *StorDbCfg) { + cln = &StorDbCfg{ + Type: dbcfg.Type, + Host: dbcfg.Host, + Port: dbcfg.Port, + Name: dbcfg.Name, + User: dbcfg.User, + Password: dbcfg.Password, + + Items: make(map[string]*ItemOpt), + Opts: make(map[string]interface{}), + } for key, item := range dbcfg.Items { - items[key] = item.Clone() + cln.Items[key] = item.Clone() } - return &StorDbCfg{ - Type: dbcfg.Type, - Host: dbcfg.Host, - Port: dbcfg.Port, - Name: dbcfg.Name, - User: dbcfg.User, - Password: dbcfg.Password, - StringIndexedFields: dbcfg.StringIndexedFields, - PrefixIndexedFields: dbcfg.PrefixIndexedFields, - RmtConns: dbcfg.RmtConns, - RplConns: dbcfg.RplConns, - Items: items, - Opts: dbcfg.Opts, + for key, val := range dbcfg.Opts { + cln.Opts[key] = val } + if dbcfg.StringIndexedFields != nil { + cln.StringIndexedFields = make([]string, len(dbcfg.StringIndexedFields)) + for i, idx := range dbcfg.StringIndexedFields { + cln.StringIndexedFields[i] = idx + } + } + if dbcfg.PrefixIndexedFields != nil { + cln.PrefixIndexedFields = make([]string, len(dbcfg.PrefixIndexedFields)) + for i, idx := range dbcfg.PrefixIndexedFields { + cln.PrefixIndexedFields[i] = idx + } + } + if dbcfg.RmtConns != nil { + cln.RmtConns = make([]string, len(dbcfg.RmtConns)) + for i, conn := range dbcfg.RmtConns { + cln.RmtConns[i] = conn + } + } + if dbcfg.RplConns != nil { + cln.RplConns = make([]string, len(dbcfg.RplConns)) + for i, conn := range dbcfg.RplConns { + cln.RplConns[i] = conn + } + } + return } +// AsMapInterface returns the config as a map[string]interface{} func (dbcfg *StorDbCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.DataDbTypeCfg: utils.Meta + dbcfg.Type, diff --git a/config/stordbcfg_test.go b/config/stordbcfg_test.go index 0a102000c..5829d8b2b 100644 --- a/config/stordbcfg_test.go +++ b/config/stordbcfg_test.go @@ -83,7 +83,7 @@ func TestStoreDbCfgloadFromJsonCfgCase1(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.storDbCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsonCfg.storDbCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected.Items[utils.MetaSessionsCosts], jsonCfg.storDbCfg.Items[utils.MetaSessionsCosts]) { t.Errorf("Expected %+v \n, recevied %+v", utils.ToJSON(expected.Items[utils.MetaSessionsCosts]), @@ -104,7 +104,7 @@ func TestStoreDbCfgloadFromJsonCfgCase2(t *testing.T) { expected := "Replication connection ID needs to be different than *internal" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.storDbCfg.loadFromJsonCfg(storDbJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.storDbCfg.loadFromJSONCfg(storDbJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", storDbJSON, expected) } } @@ -116,7 +116,7 @@ func TestStoreDbCfgloadFromJsonCfgCase3(t *testing.T) { expected := "Remote connection ID needs to be different than *internal" if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.storDbCfg.loadFromJsonCfg(storDbJSON); err == nil || err.Error() != expected { + } else if err = jsonCfg.storDbCfg.loadFromJSONCfg(storDbJSON); err == nil || err.Error() != expected { t.Errorf("Expected %+v, received %+v", storDbJSON, expected) } } @@ -148,7 +148,7 @@ func TestStoreDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -168,7 +168,7 @@ func TestStoreDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -188,7 +188,7 @@ func TestStoreDbCfgloadFromJsonCfgPort(t *testing.T) { t.Error(err) } else if jsnDataDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN); err != nil { t.Error(err) - } else if err = dbcfg.loadFromJsonCfg(jsnDataDbCfg); err != nil { + } else if err = dbcfg.loadFromJSONCfg(jsnDataDbCfg); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, dbcfg) { t.Errorf("Expected: %+v , received: %+v", expected, dbcfg) @@ -264,3 +264,60 @@ func TestStorDbCfgAsMapInterface(t *testing.T) { } } } + +func TestStorDbCfgClone(t *testing.T) { + ban := &StorDbCfg{ + Type: utils.MYSQL, + Host: "127.0.0.1", + Port: "-1", + Name: utils.CGRATES, + User: utils.CGRATES, + Password: "pass123", + StringIndexedFields: []string{"*req.index1"}, + PrefixIndexedFields: []string{"*req.index1"}, + RmtConns: []string{"*conn1"}, + RplConns: []string{"*conn1"}, + Items: map[string]*ItemOpt{ + utils.MetaSessionsCosts: { + Remote: true, + Replicate: true, + }, + utils.MetaCDRs: { + Remote: true, + Replicate: false, + }, + }, + Opts: map[string]interface{}{ + utils.MaxOpenConnsCfg: 100., + utils.MaxIdleConnsCfg: 10., + utils.ConnMaxLifetimeCfg: 0., + utils.QueryTimeoutCfg: "10s", + utils.SSLModeCfg: "disable", + }, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.StringIndexedFields[0] = ""; ban.StringIndexedFields[0] != "*req.index1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.PrefixIndexedFields[0] = ""; ban.PrefixIndexedFields[0] != "*req.index1" { + t.Errorf("Expected clone to not modify the cloned") + } + + if rcv.RmtConns[0] = ""; ban.RmtConns[0] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.RplConns[0] = ""; ban.RplConns[0] != "*conn1" { + t.Errorf("Expected clone to not modify the cloned") + } + + if rcv.Items[utils.MetaCDRs].Remote = false; !ban.Items[utils.MetaCDRs].Remote { + t.Errorf("Expected clone to not modify the cloned") + } + if rcv.Opts[utils.SSLModeCfg] = ""; ban.Opts[utils.SSLModeCfg] != "disable" { + t.Errorf("Expected clone to not modify the cloned") + } + +} diff --git a/config/tlscfg.go b/config/tlscfg.go index d3bb3a763..8fe87332c 100644 --- a/config/tlscfg.go +++ b/config/tlscfg.go @@ -20,8 +20,8 @@ package config import "github.com/cgrates/cgrates/utils" -// AttributeSCfg is the configuration of attribute service -type TlsCfg struct { +// TLSCfg is the configuration for tls +type TLSCfg struct { ServerCerificate string ServerKey string ServerPolicy int @@ -31,7 +31,7 @@ type TlsCfg struct { CaCertificate string } -func (tls *TlsCfg) loadFromJsonCfg(jsnCfg *TlsJsonCfg) (err error) { +func (tls *TLSCfg) loadFromJSONCfg(jsnCfg *TlsJsonCfg) (err error) { if jsnCfg == nil { return nil } @@ -59,7 +59,8 @@ func (tls *TlsCfg) loadFromJsonCfg(jsnCfg *TlsJsonCfg) (err error) { return } -func (tls *TlsCfg) AsMapInterface() map[string]interface{} { +// AsMapInterface returns the config as a map[string]interface{} +func (tls *TLSCfg) AsMapInterface() map[string]interface{} { return map[string]interface{}{ utils.ServerCerificateCfg: tls.ServerCerificate, utils.ServerKeyCfg: tls.ServerKey, @@ -71,3 +72,16 @@ func (tls *TlsCfg) AsMapInterface() map[string]interface{} { } } + +// Clone returns a deep copy of TLSCfg +func (tls TLSCfg) Clone() *TLSCfg { + return &TLSCfg{ + ServerCerificate: tls.ServerCerificate, + ServerKey: tls.ServerKey, + ServerPolicy: tls.ServerPolicy, + ServerName: tls.ServerName, + ClientCerificate: tls.ClientCerificate, + ClientKey: tls.ClientKey, + CaCertificate: tls.CaCertificate, + } +} diff --git a/config/tlscfg_test.go b/config/tlscfg_test.go index d457e9a8c..40f917bb6 100644 --- a/config/tlscfg_test.go +++ b/config/tlscfg_test.go @@ -34,7 +34,7 @@ func TestTlsCfgloadFromJsonCfg(t *testing.T) { Server_name: utils.StringPointer("TestServerName"), Server_policy: utils.IntPointer(3), } - expected := &TlsCfg{ + expected := &TLSCfg{ ServerCerificate: "path/To/Server/Cert", ServerKey: "path/To/Server/Key", CaCertificate: "path/To/CA/Cert", @@ -45,7 +45,7 @@ func TestTlsCfgloadFromJsonCfg(t *testing.T) { } if jsonCfg, err := NewDefaultCGRConfig(); err != nil { t.Error(err) - } else if err = jsonCfg.tlsCfg.loadFromJsonCfg(cfgJSON); err != nil { + } else if err = jsonCfg.tlsCfg.loadFromJSONCfg(cfgJSON); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, jsonCfg.tlsCfg) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(jsonCfg.tlsCfg)) @@ -99,3 +99,22 @@ func TestTlsCfgAsMapInterface1(t *testing.T) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv)) } } + +func TestTLSCfgClone(t *testing.T) { + ban := &TLSCfg{ + ServerCerificate: "path/To/Server/Cert", + ServerKey: "path/To/Server/Key", + CaCertificate: "path/To/CA/Cert", + ClientCerificate: "path/To/Client/Cert", + ClientKey: "path/To/Client/Key", + ServerName: "TestServerName", + ServerPolicy: 3, + } + rcv := ban.Clone() + if !reflect.DeepEqual(ban, rcv) { + t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv)) + } + if rcv.ServerPolicy = 0; ban.ServerPolicy != 3 { + t.Errorf("Expected clone to not modify the cloned") + } +} diff --git a/loaders/loader.go b/loaders/loader.go index 5ae4881a6..206fc51af 100644 --- a/loaders/loader.go +++ b/loaders/loader.go @@ -46,7 +46,7 @@ func NewLoader(dm *engine.DataManager, cfg *config.LoaderSCfg, enabled: cfg.Enabled, tenant: cfg.Tenant, dryRun: cfg.DryRun, - ldrID: cfg.Id, + ldrID: cfg.ID, tpInDir: cfg.TpInDir, tpOutDir: cfg.TpOutDir, lockFilename: cfg.LockFileName, diff --git a/loaders/loaders.go b/loaders/loaders.go index 34e656b1c..ace113f50 100644 --- a/loaders/loaders.go +++ b/loaders/loaders.go @@ -34,7 +34,7 @@ func NewLoaderService(dm *engine.DataManager, ldrsCfg []*config.LoaderSCfg, ldrS = &LoaderService{ldrs: make(map[string]*Loader)} for _, ldrCfg := range ldrsCfg { if ldrCfg.Enabled { - ldrS.ldrs[ldrCfg.Id] = NewLoader(dm, ldrCfg, timezone, filterS, connMgr, ldrCfg.CacheSConns) + ldrS.ldrs[ldrCfg.ID] = NewLoader(dm, ldrCfg, timezone, filterS, connMgr, ldrCfg.CacheSConns) } } return @@ -141,7 +141,7 @@ func (ldrS *LoaderService) Reload(dm *engine.DataManager, ldrsCfg []*config.Load ldrS.ldrs = make(map[string]*Loader) for _, ldrCfg := range ldrsCfg { if ldrCfg.Enabled { - ldrS.ldrs[ldrCfg.Id] = NewLoader(dm, ldrCfg, timezone, filterS, connMgr, ldrCfg.CacheSConns) + ldrS.ldrs[ldrCfg.ID] = NewLoader(dm, ldrCfg, timezone, filterS, connMgr, ldrCfg.CacheSConns) } } ldrS.Unlock() diff --git a/migrator/rateprofiles_it_test.go b/migrator/rateprofiles_it_test.go index 7deb598c3..202cd73d7 100644 --- a/migrator/rateprofiles_it_test.go +++ b/migrator/rateprofiles_it_test.go @@ -183,7 +183,6 @@ func testRatePrfITMigrateAndMove(t *testing.T) { ID: "RP1", FilterIDs: []string{"*string:~*req.Subject:1001"}, Weight: 0, - ConnectFee: 0.1, RoundingMethod: "*up", RoundingDecimals: 4, MinCost: 0.1, @@ -196,9 +195,9 @@ func testRatePrfITMigrateAndMove(t *testing.T) { Weight: 0, IntervalRates: []*engine.IntervalRate{ { - Value: 0.12, - Unit: time.Minute, - Increment: time.Minute, + RecurrentFee: 0.12, + Unit: time.Minute, + Increment: time.Minute, }, }, Blocker: false, @@ -209,9 +208,9 @@ func testRatePrfITMigrateAndMove(t *testing.T) { Weight: 10, IntervalRates: []*engine.IntervalRate{ { - Value: 0.06, - Unit: time.Minute, - Increment: time.Second, + RecurrentFee: 0.06, + Unit: time.Minute, + Increment: time.Second, }, }, Blocker: false, diff --git a/services/httpagent.go b/services/httpagent.go index aa7b95801..f90440d41 100644 --- a/services/httpagent.go +++ b/services/httpagent.go @@ -64,7 +64,7 @@ func (ha *HTTPAgent) Start() (err error) { ha.Lock() utils.Logger.Info(fmt.Sprintf("<%s> successfully started HTTPAgent", utils.HTTPAgent)) for _, agntCfg := range ha.cfg.HTTPAgentCfg() { - ha.server.RegisterHttpHandler(agntCfg.Url, + ha.server.RegisterHttpHandler(agntCfg.URL, agents.NewHTTPAgent(ha.connMgr, agntCfg.SessionSConns, filterS, ha.cfg.GeneralCfg().DefaultTenant, agntCfg.RequestPayload, agntCfg.ReplyPayload, agntCfg.RequestProcessors)) diff --git a/sessions/sessions.go b/sessions/sessions.go index ec64590be..c10c277c4 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -46,7 +46,7 @@ var ( func NewSessionS(cgrCfg *config.CGRConfig, dm *engine.DataManager, connMgr *engine.ConnManager) *SessionS { - cgrCfg.SessionSCfg().SessionIndexes[utils.OriginID] = true // Make sure we have indexing for OriginID since it is a requirement on prefix searching + cgrCfg.SessionSCfg().SessionIndexes.Add(utils.OriginID) // Make sure we have indexing for OriginID since it is a requirement on prefix searching return &SessionS{ cgrCfg: cgrCfg, @@ -55,10 +55,10 @@ func NewSessionS(cgrCfg *config.CGRConfig, biJClnts: make(map[rpcclient.ClientConnector]string), biJIDs: make(map[string]*biJClient), aSessions: make(map[string]*Session), - aSessionsIdx: make(map[string]map[string]map[string]utils.StringMap), + aSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), aSessionsRIdx: make(map[string][]*riFieldNameVal), pSessions: make(map[string]*Session), - pSessionsIdx: make(map[string]map[string]map[string]utils.StringMap), + pSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), pSessionsRIdx: make(map[string][]*riFieldNameVal), } } @@ -83,14 +83,14 @@ type SessionS struct { aSessions map[string]*Session // group sessions per sessionId aSIMux sync.RWMutex // protects aSessionsIdx - aSessionsIdx map[string]map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue][cgrID]utils.StringMap[runID]sID + aSessionsIdx map[string]map[string]map[string]utils.StringSet // map[fieldName]map[fieldValue][cgrID]utils.StringSet[runID]sID aSessionsRIdx map[string][]*riFieldNameVal // reverse indexes for active sessions, used on remove pSsMux sync.RWMutex // protects pSessions pSessions map[string]*Session // group passive sessions based on cgrID pSIMux sync.RWMutex // protects pSessionsIdx - pSessionsIdx map[string]map[string]map[string]utils.StringMap // map[fieldName]map[fieldValue][cgrID]utils.StringMap[runID]sID + pSessionsIdx map[string]map[string]map[string]utils.StringSet // map[fieldName]map[fieldValue][cgrID]utils.StringSet[runID]sID pSessionsRIdx map[string][]*riFieldNameVal // reverse indexes for passive sessions, used on remove } @@ -857,15 +857,15 @@ func (sS *SessionS) indexSession(s *Session, pSessions bool) { fieldVal = utils.MetaEmpty } if _, hasFieldName := ssIndx[fieldName]; !hasFieldName { // Init it here - ssIndx[fieldName] = make(map[string]map[string]utils.StringMap) + ssIndx[fieldName] = make(map[string]map[string]utils.StringSet) } if _, hasFieldVal := ssIndx[fieldName][fieldVal]; !hasFieldVal { - ssIndx[fieldName][fieldVal] = make(map[string]utils.StringMap) + ssIndx[fieldName][fieldVal] = make(map[string]utils.StringSet) } if _, hasCGRID := ssIndx[fieldName][fieldVal][s.CGRID]; !hasCGRID { - ssIndx[fieldName][fieldVal][s.CGRID] = make(utils.StringMap) + ssIndx[fieldName][fieldVal][s.CGRID] = make(utils.StringSet) } - ssIndx[fieldName][fieldVal][s.CGRID][sr.CD.RunID] = true + ssIndx[fieldName][fieldVal][s.CGRID].Add(sr.CD.RunID) // reverse index if _, hasIt := ssRIdx[s.CGRID]; !hasIt { @@ -925,7 +925,7 @@ func (sS *SessionS) getIndexedFilters(tenant string, fltrs []string) ( for _, fltr := range f.Rules { fldName := strings.TrimPrefix(fltr.Element, utils.DynamicDataPrefix+utils.MetaReq+utils.NestingSep) // remove ~req. prefix if fltr.Type != utils.MetaString || - !sS.cgrCfg.SessionSCfg().SessionIndexes.HasKey(fldName) { + !sS.cgrCfg.SessionSCfg().SessionIndexes.Has(fldName) { unindexedFltr = append(unindexedFltr, fltr) continue } @@ -937,7 +937,7 @@ func (sS *SessionS) getIndexedFilters(tenant string, fltrs []string) ( // getSessionIDsMatchingIndexes returns map[matchedFieldName]possibleMatchedFieldVal so we optimize further to avoid checking them func (sS *SessionS) getSessionIDsMatchingIndexes(fltrs map[string][]string, - pSessions bool) ([]string, map[string]utils.StringMap) { + pSessions bool) ([]string, map[string]utils.StringSet) { idxMux := &sS.aSIMux ssIndx := sS.aSessionsIdx if pSessions { @@ -946,10 +946,10 @@ func (sS *SessionS) getSessionIDsMatchingIndexes(fltrs map[string][]string, } idxMux.RLock() defer idxMux.RUnlock() - matchingSessions := make(map[string]utils.StringMap) + matchingSessions := make(map[string]utils.StringSet) checkNr := 0 - getMatchingIndexes := func(fltrName string, values []string) (matchingSessionsbyValue map[string]utils.StringMap) { - matchingSessionsbyValue = make(map[string]utils.StringMap) + getMatchingIndexes := func(fltrName string, values []string) (matchingSessionsbyValue map[string]utils.StringSet) { + matchingSessionsbyValue = make(map[string]utils.StringSet) // fltrName = strings.TrimPrefix(fltrName, utils.DynamicDataPrefix+utils.MetaReq+utils.NestingSep) // if _, hasFldName := ssIndx[fltrName]; !hasFldName { return @@ -960,10 +960,10 @@ func (sS *SessionS) getSessionIDsMatchingIndexes(fltrs map[string][]string, } for cgrID, runIDs := range ssIndx[fltrName][fltrVal] { if _, hasCGRID := matchingSessionsbyValue[cgrID]; !hasCGRID { - matchingSessionsbyValue[cgrID] = utils.NewStringMap() + matchingSessionsbyValue[cgrID] = utils.StringSet{} } for runID := range runIDs { - matchingSessionsbyValue[cgrID][runID] = true + matchingSessionsbyValue[cgrID].Add(runID) } } } @@ -983,14 +983,14 @@ func (sS *SessionS) getSessionIDsMatchingIndexes(fltrs map[string][]string, continue } else { for runID := range runIDs { - if !matchedRunIDs.HasKey(runID) { + if !matchedRunIDs.Has(runID) { delete(matchingSessions[cgrID], runID) } } } } if len(matchingSessions) == 0 { - return make([]string, 0), make(map[string]utils.StringMap) + return make([]string, 0), make(map[string]utils.StringSet) } } cgrIDs := []string{} @@ -1044,7 +1044,7 @@ func (sS *SessionS) filterSessions(sf *utils.SessionFilter, psv bool) (aSs []*Ex s.RLock() runIDs := matchingSRuns[s.CGRID] for _, sr := range s.SRuns { - if len(cgrIDs) != 0 && !runIDs.HasKey(sr.CD.RunID) { + if len(cgrIDs) != 0 && !runIDs.Has(sr.CD.RunID) { continue } if pass(unindx, sr.Event) { @@ -1099,7 +1099,7 @@ func (sS *SessionS) filterSessionsCount(sf *utils.SessionFilter, psv bool) (coun s.RLock() runIDs := matchingSRuns[s.CGRID] for _, sr := range s.SRuns { - if len(cgrIDs) != 0 && !runIDs.HasKey(sr.CD.RunID) { + if len(cgrIDs) != 0 && !runIDs.Has(sr.CD.RunID) { continue } if pass(unindx, sr.Event) { diff --git a/sessions/sessions_test.go b/sessions/sessions_test.go index ac9291ef9..67b6c340b 100644 --- a/sessions/sessions_test.go +++ b/sessions/sessions_test.go @@ -89,11 +89,11 @@ func TestIsIndexed(t *testing.T) { func TestSessionSIndexAndUnindexSessions(t *testing.T) { sSCfg, _ := config.NewDefaultCGRConfig() - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "Tenant": true, - "Account": true, - "Extra3": true, - "Extra4": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "Tenant": {}, + "Account": {}, + "Extra3": {}, + "Extra4": {}, } sS := NewSessionS(sSCfg, nil, nil) sEv := engine.NewMapEvent(map[string]interface{}{ @@ -133,30 +133,30 @@ func TestSessionSIndexAndUnindexSessions(t *testing.T) { } cgrID := GetSetCGRID(sEv) sS.indexSession(session, false) - eIndexes := map[string]map[string]map[string]utils.StringMap{ + eIndexes := map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "12345": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + "12345": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, }, "Tenant": { - "cgrates.org": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + "cgrates.org": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, }, "Account": { - "account1": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + "account1": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, }, "Extra3": { - utils.MetaEmpty: map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + utils.MetaEmpty: map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, }, "Extra4": { - utils.NOT_AVAILABLE: map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + utils.NOT_AVAILABLE: map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, }, } @@ -222,52 +222,52 @@ func TestSessionSIndexAndUnindexSessions(t *testing.T) { }, } sS.indexSession(session3, false) - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "12345": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + "12345": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, - "12346": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "12346": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, - "12347": map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + "12347": map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, }, "Tenant": { - "cgrates.org": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, - cgrID3: {utils.MetaDefault: true}, + "cgrates.org": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, + cgrID3: {utils.MetaDefault: {}}, }, - "itsyscom.com": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "itsyscom.com": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Account": { - "account1": map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, + "account1": map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, }, - "account2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, - cgrID3: {utils.MetaDefault: true}, + "account2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, + cgrID3: {utils.MetaDefault: {}}, }, }, "Extra3": { - utils.MetaEmpty: map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, - cgrID2: {utils.MetaDefault: true}, + utils.MetaEmpty: map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, + cgrID2: {utils.MetaDefault: {}}, }, - utils.NOT_AVAILABLE: map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + utils.NOT_AVAILABLE: map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, }, "Extra4": { - utils.NOT_AVAILABLE: map[string]utils.StringMap{ - cgrID: {utils.MetaDefault: true}, - cgrID3: {utils.MetaDefault: true}, + utils.NOT_AVAILABLE: map[string]utils.StringSet{ + cgrID: {utils.MetaDefault: {}}, + cgrID3: {utils.MetaDefault: {}}, }, - "info2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "info2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, } @@ -304,43 +304,43 @@ func TestSessionSIndexAndUnindexSessions(t *testing.T) { } // Unidex first session sS.unindexSession(cgrID, false) - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "12346": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "12346": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, - "12347": map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + "12347": map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, }, "Tenant": { - "cgrates.org": map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + "cgrates.org": map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, - "itsyscom.com": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "itsyscom.com": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Account": { - "account2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, - cgrID3: {utils.MetaDefault: true}, + "account2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, + cgrID3: {utils.MetaDefault: {}}, }, }, "Extra3": { - utils.MetaEmpty: map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + utils.MetaEmpty: map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, - utils.NOT_AVAILABLE: map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + utils.NOT_AVAILABLE: map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, }, "Extra4": { - "info2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "info2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, - utils.NOT_AVAILABLE: map[string]utils.StringMap{ - cgrID3: {utils.MetaDefault: true}, + utils.NOT_AVAILABLE: map[string]utils.StringSet{ + cgrID3: {utils.MetaDefault: {}}, }, }, } @@ -368,30 +368,30 @@ func TestSessionSIndexAndUnindexSessions(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", eRIdxes, sS.aSessionsRIdx) } sS.unindexSession(cgrID3, false) - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "12346": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "12346": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Tenant": { - "itsyscom.com": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "itsyscom.com": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Account": { - "account2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "account2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Extra3": { - utils.MetaEmpty: map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + utils.MetaEmpty: map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, "Extra4": { - "info2": map[string]utils.StringMap{ - cgrID2: {utils.MetaDefault: true}, + "info2": map[string]utils.StringSet{ + cgrID2: {utils.MetaDefault: {}}, }, }, } @@ -455,10 +455,10 @@ func TestSessionSRegisterAndUnregisterASessions(t *testing.T) { } //verify if the index was created according to session - eIndexes := map[string]map[string]map[string]utils.StringMap{ + eIndexes := map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "111": map[string]utils.StringMap{ - "session1": {utils.MetaDefault: true}, + "111": map[string]utils.StringSet{ + "session1": {utils.MetaDefault: {}}, }, }, } @@ -512,13 +512,13 @@ func TestSessionSRegisterAndUnregisterASessions(t *testing.T) { } // verify if the index was created according to session - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "111": map[string]utils.StringMap{ - "session1": {utils.MetaDefault: true}, + "111": map[string]utils.StringSet{ + "session1": {utils.MetaDefault: {}}, }, - "222": map[string]utils.StringMap{ - "session2": {utils.MetaDefault: true}, + "222": map[string]utils.StringSet{ + "session2": {utils.MetaDefault: {}}, }, }, } @@ -588,10 +588,10 @@ func TestSessionSRegisterAndUnregisterASessions(t *testing.T) { t.Error("Expectinv: false, received: true") } - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "222": map[string]utils.StringMap{ - "session2": {utils.MetaDefault: true}, + "222": map[string]utils.StringSet{ + "session2": {utils.MetaDefault: {}}, }, }, } @@ -615,7 +615,7 @@ func TestSessionSRegisterAndUnregisterASessions(t *testing.T) { sS.unregisterSession("session2", false) - eIndexes = map[string]map[string]map[string]utils.StringMap{} + eIndexes = map[string]map[string]map[string]utils.StringSet{} if !reflect.DeepEqual(eIndexes, sS.aSessionsIdx) { t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eIndexes), utils.ToJSON(sS.aSessionsIdx)) @@ -673,10 +673,10 @@ func TestSessionSRegisterAndUnregisterPSessions(t *testing.T) { } //verify if the index was created according to session - eIndexes := map[string]map[string]map[string]utils.StringMap{ + eIndexes := map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "111": map[string]utils.StringMap{ - "session1": {utils.MetaDefault: true}, + "111": map[string]utils.StringSet{ + "session1": {utils.MetaDefault: {}}, }, }, } @@ -733,13 +733,13 @@ func TestSessionSRegisterAndUnregisterPSessions(t *testing.T) { } //verify if the index was created according to session - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "111": map[string]utils.StringMap{ - "session1": {utils.MetaDefault: true}, + "111": map[string]utils.StringSet{ + "session1": {utils.MetaDefault: {}}, }, - "222": map[string]utils.StringMap{ - "session2": {utils.MetaDefault: true}, + "222": map[string]utils.StringSet{ + "session2": {utils.MetaDefault: {}}, }, }, } @@ -802,10 +802,10 @@ func TestSessionSRegisterAndUnregisterPSessions(t *testing.T) { //unregister the session and check if the index was removed sS.unregisterSession("session1", true) - eIndexes = map[string]map[string]map[string]utils.StringMap{ + eIndexes = map[string]map[string]map[string]utils.StringSet{ "OriginID": { - "222": map[string]utils.StringMap{ - "session2": {utils.MetaDefault: true}, + "222": map[string]utils.StringSet{ + "session2": {utils.MetaDefault: {}}, }, }, } @@ -829,7 +829,7 @@ func TestSessionSRegisterAndUnregisterPSessions(t *testing.T) { sS.unregisterSession("session2", true) - eIndexes = map[string]map[string]map[string]utils.StringMap{} + eIndexes = map[string]map[string]map[string]utils.StringSet{} if !reflect.DeepEqual(eIndexes, sS.pSessionsIdx) { t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eIndexes), utils.ToJSON(sS.pSessionsIdx)) @@ -1632,8 +1632,8 @@ func TestSessionSGetIndexedFilters(t *testing.T) { } else if !reflect.DeepEqual(expUindx, rplyUnindx) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expUindx), utils.ToJSON(rplyUnindx)) } - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, } sS = NewSessionS(sSCfg, engine.NewDataManager(mpStr, config.CgrConfig().CacheCfg(), nil), nil) expIndx = map[string][]string{(utils.ToR): {utils.VOICE}} @@ -1666,8 +1666,8 @@ func TestSessionSGetIndexedFilters(t *testing.T) { func TestSessionSgetSessionIDsMatchingIndexes(t *testing.T) { sSCfg, _ := config.NewDefaultCGRConfig() - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, } sS := NewSessionS(sSCfg, nil, nil) sEv := engine.NewMapEvent(map[string]interface{}{ @@ -1709,17 +1709,17 @@ func TestSessionSgetSessionIDsMatchingIndexes(t *testing.T) { sS.indexSession(session, false) indx := map[string][]string{"ToR": {utils.VOICE, utils.DATA}} expCGRIDs := []string{cgrID} - expmatchingSRuns := map[string]utils.StringMap{cgrID: { - "RunID": true, + expmatchingSRuns := map[string]utils.StringSet{cgrID: { + "RunID": {}, }} if cgrIDs, matchingSRuns := sS.getSessionIDsMatchingIndexes(indx, false); !reflect.DeepEqual(expCGRIDs, cgrIDs) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expCGRIDs), utils.ToJSON(cgrIDs)) } else if !reflect.DeepEqual(expmatchingSRuns, matchingSRuns) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expmatchingSRuns), utils.ToJSON(matchingSRuns)) } - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, - "Extra3": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, + "Extra3": {}, } sS = NewSessionS(sSCfg, nil, nil) sS.indexSession(session, false) @@ -1728,7 +1728,7 @@ func TestSessionSgetSessionIDsMatchingIndexes(t *testing.T) { "Extra2": {"55"}, } expCGRIDs = []string{} - expmatchingSRuns = map[string]utils.StringMap{} + expmatchingSRuns = map[string]utils.StringSet{} if cgrIDs, matchingSRuns := sS.getSessionIDsMatchingIndexes(indx, false); !reflect.DeepEqual(expCGRIDs, cgrIDs) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expCGRIDs), utils.ToJSON(cgrIDs)) } else if !reflect.DeepEqual(expmatchingSRuns, matchingSRuns) { @@ -1751,9 +1751,9 @@ func TestSessionSgetSessionIDsMatchingIndexes(t *testing.T) { }, }, } - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, - "Extra2": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, + "Extra2": {}, } sS = NewSessionS(sSCfg, nil, nil) sS.indexSession(session, true) @@ -1763,8 +1763,8 @@ func TestSessionSgetSessionIDsMatchingIndexes(t *testing.T) { } expCGRIDs = []string{cgrID} - expmatchingSRuns = map[string]utils.StringMap{cgrID: { - "RunID": true, + expmatchingSRuns = map[string]utils.StringSet{cgrID: { + "RunID": {}, }} if cgrIDs, matchingSRuns := sS.getSessionIDsMatchingIndexes(indx, true); !reflect.DeepEqual(expCGRIDs, cgrIDs) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expCGRIDs), utils.ToJSON(cgrIDs)) @@ -1786,10 +1786,10 @@ func TestNewSessionS(t *testing.T) { biJClnts: make(map[rpcclient.ClientConnector]string), biJIDs: make(map[string]*biJClient), aSessions: make(map[string]*Session), - aSessionsIdx: make(map[string]map[string]map[string]utils.StringMap), + aSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), aSessionsRIdx: make(map[string][]*riFieldNameVal), pSessions: make(map[string]*Session), - pSessionsIdx: make(map[string]map[string]map[string]utils.StringMap), + pSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), pSessionsRIdx: make(map[string][]*riFieldNameVal), } sS := NewSessionS(cgrCGF, nil, nil) @@ -1989,8 +1989,8 @@ func TestSessionSgetSession(t *testing.T) { func TestSessionSfilterSessions(t *testing.T) { sSCfg, _ := config.NewDefaultCGRConfig() - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, } sS := NewSessionS(sSCfg, nil, nil) sEv := engine.NewMapEvent(map[string]interface{}{ @@ -2119,9 +2119,9 @@ func TestSessionSfilterSessions(t *testing.T) { if sess := sS.filterSessions(fltrs, false); !reflect.DeepEqual(expSess, sess) { t.Errorf("Expected %s , received: %s", utils.ToJSON(expSess), utils.ToJSON(sess)) } - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, - "Extra3": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, + "Extra3": {}, } sS = NewSessionS(sSCfg, nil, nil) sS.registerSession(session, false) @@ -2165,8 +2165,8 @@ func TestSessionSfilterSessions(t *testing.T) { func TestSessionSfilterSessionsCount(t *testing.T) { sSCfg, _ := config.NewDefaultCGRConfig() - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, } sS := NewSessionS(sSCfg, nil, nil) sEv := engine.NewMapEvent(map[string]interface{}{ @@ -2231,9 +2231,9 @@ func TestSessionSfilterSessionsCount(t *testing.T) { if noSess := sS.filterSessionsCount(fltrs, false); noSess != 1 { t.Errorf("Expected %v , received: %s", 1, utils.ToJSON(noSess)) } - sSCfg.SessionSCfg().SessionIndexes = utils.StringMap{ - "ToR": true, - "Extra3": true, + sSCfg.SessionSCfg().SessionIndexes = utils.StringSet{ + "ToR": {}, + "Extra3": {}, } sS = NewSessionS(sSCfg, nil, nil) sS.registerSession(session, false)