From 83c18d469b8df911ab1a93df9c03f68ae80aba2e Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Fri, 13 Nov 2015 16:31:06 +0200 Subject: [PATCH] added DerivedChargers DestinationIds filter --- apier/v1/apier_local_test.go | 8 ++-- apier/v1/derivedcharging.go | 10 ++-- apier/v1/derivedcharging_test.go | 8 ++-- engine/cdrs.go | 2 +- engine/handler_derivedcharging.go | 28 +++++++++-- engine/loader_csv_test.go | 34 +++++++------- engine/model_helpers.go | 2 +- engine/model_helpers_test.go | 4 +- engine/models.go | 35 +++++++------- engine/responder.go | 14 +++--- engine/responder_test.go | 18 ++++---- engine/storage_csv.go | 4 +- engine/storage_interface.go | 4 +- engine/storage_map.go | 8 ++-- engine/storage_mongo.go | 12 ++--- engine/storage_redis.go | 8 ++-- engine/storage_redis_local_test.go | 4 +- engine/tp_reader.go | 12 +++-- utils/apitpdata.go | 3 +- utils/derivedchargers.go | 74 ++++++++++++++++-------------- utils/derivedchargers_test.go | 26 ++++++----- utils/map.go | 8 +++- 22 files changed, 185 insertions(+), 141 deletions(-) diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 3b804fbf0..7a3d02809 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -1467,12 +1467,12 @@ func TestApierLocalSetDC(t *testing.T) { if !*testLocal { return } - dcs1 := utils.DerivedChargers{ + dcs1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} attrs := AttrSetDerivedChargers{Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: dcs1} var reply string if err := rater.Call("ApierV1.SetDerivedChargers", attrs, &reply); err != nil { @@ -1487,12 +1487,12 @@ func TestApierLocalGetDC(t *testing.T) { return } attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} - eDcs := utils.DerivedChargers{ + eDcs := utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} var dcs utils.DerivedChargers if err := rater.Call("ApierV1.GetDerivedChargers", attrs, &dcs); err != nil { t.Error("Unexpected error", err.Error()) diff --git a/apier/v1/derivedcharging.go b/apier/v1/derivedcharging.go index ccaae69a1..2eeefda6b 100644 --- a/apier/v1/derivedcharging.go +++ b/apier/v1/derivedcharging.go @@ -33,15 +33,15 @@ func (self *ApierV1) GetDerivedChargers(attrs utils.AttrDerivedChargers, reply * if hDc, err := engine.HandleGetDerivedChargers(self.RatingDb, &attrs); err != nil { return utils.NewErrServerError(err) } else if hDc != nil { - *reply = hDc + *reply = *hDc } return nil } type AttrSetDerivedChargers struct { - Direction, Tenant, Category, Account, Subject string - DerivedChargers utils.DerivedChargers - Overwrite bool // Do not overwrite if present in redis + Direction, Tenant, Category, Account, Subject, DestinationIds string + DerivedChargers *utils.DerivedChargers + Overwrite bool // Do not overwrite if present in redis } func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *string) (err error) { @@ -60,7 +60,7 @@ func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *str if len(attrs.Subject) == 0 { attrs.Subject = utils.ANY } - for _, dc := range attrs.DerivedChargers { + for _, dc := range attrs.DerivedChargers.Chargers { if _, err = utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP); err != nil { // Make sure rules are OK before loading in db return fmt.Errorf("%s:%s", utils.ErrParserError.Error(), err.Error()) } diff --git a/apier/v1/derivedcharging_test.go b/apier/v1/derivedcharging_test.go index ccbfb5f41..2a12f14d8 100644 --- a/apier/v1/derivedcharging_test.go +++ b/apier/v1/derivedcharging_test.go @@ -48,12 +48,12 @@ func TestGetEmptyDC(t *testing.T) { */ func TestSetDC(t *testing.T) { - dcs1 := utils.DerivedChargers{ + dcs1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} attrs := AttrSetDerivedChargers{Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: dcs1} var reply string if err := apierDcT.SetDerivedChargers(attrs, &reply); err != nil { @@ -65,12 +65,12 @@ func TestSetDC(t *testing.T) { func TestGetDC(t *testing.T) { attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} - eDcs := utils.DerivedChargers{ + eDcs := utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} var dcs utils.DerivedChargers if err := apierDcT.GetDerivedChargers(attrs, &dcs); err != nil { t.Error("Unexpected error", err.Error()) diff --git a/engine/cdrs.go b/engine/cdrs.go index 642a4bf61..eab196d26 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -273,7 +273,7 @@ func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error())) return nil, err } - for _, dc := range dcs { + for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { diff --git a/engine/handler_derivedcharging.go b/engine/handler_derivedcharging.go index ecf0a0d69..d5dc087f8 100644 --- a/engine/handler_derivedcharging.go +++ b/engine/handler_derivedcharging.go @@ -19,12 +19,13 @@ along with this program. If not, see package engine import ( + "github.com/cgrates/cgrates/cache2go" "github.com/cgrates/cgrates/utils" ) // Handles retrieving of DerivedChargers profile based on longest match from AccountingDb -func HandleGetDerivedChargers(ratingStorage RatingStorage, attrs *utils.AttrDerivedChargers) (utils.DerivedChargers, error) { - var dcs utils.DerivedChargers +func HandleGetDerivedChargers(ratingStorage RatingStorage, attrs *utils.AttrDerivedChargers) (*utils.DerivedChargers, error) { + dcs := &utils.DerivedChargers{} strictKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject) anySubjKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, utils.ANY) anyAcntKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, utils.ANY, utils.ANY) @@ -33,10 +34,31 @@ func HandleGetDerivedChargers(ratingStorage RatingStorage, attrs *utils.AttrDeri for _, dcKey := range []string{strictKey, anySubjKey, anyAcntKey, anyCategKey, anyTenantKey} { if dcsDb, err := ratingStorage.GetDerivedChargers(dcKey, false); err != nil && err != utils.ErrNotFound { return nil, err - } else if dcsDb != nil { + } else if dcsDb != nil && DerivedChargersMatchesDest(dcsDb, attrs.Destination) { dcs = dcsDb break } } return dcs, nil } + +func DerivedChargersMatchesDest(dcs *utils.DerivedChargers, dest string) bool { + if len(dcs.DestinationIds) == 0 || dcs.DestinationIds[utils.ANY] { + return true + } + // check destination ids + for _, p := range utils.SplitPrefix(dest, MIN_PREFIX_MATCH) { + if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil { + destIds := x.(map[interface{}]struct{}) + for value := range dcs.DestinationIds { + for idId := range destIds { + dId := idId.(string) + if value == dId { + return true + } + } + } + } + } + return false +} diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 9154b72e2..9a86b538a 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -208,10 +208,10 @@ cgrates.org,alodis,TOPUP_EMPTY_AT,,true,true ` derivedCharges = ` -#Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,PddField,AnswerTimeField,UsageField,SupplierField,DisconnectCauseField,CostField,RatedField -*out,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1/,^prepaid,,,,rif,rif,,,,,,,,, -*out,cgrates.org,call,dan,dan,extra2,,,,,,ivo,ivo,,,,,,,,, -*out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,,,,,,, +#Direction,Tenant,Category,Account,Subject,DestinationIds,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,PddField,AnswerTimeField,UsageField,SupplierField,DisconnectCauseField,CostField,RatedField +*out,cgrates.org,call,dan,dan,,extra1,^filteredHeader1/filterValue1/,^prepaid,,,,rif,rif,,,,,,,,, +*out,cgrates.org,call,dan,dan,,extra2,,,,,,ivo,ivo,,,,,,,,, +*out,cgrates.org,call,dan,*any,,extra1,,,,,,rif2,rif2,,,,,,,,, ` cdrStats = ` #Id[0],QueueLength[1],TimeWindow[2],SaveInterval[3],Metric[4],SetupInterval[5],TOR[6],CdrHost[7],CdrSource[8],ReqType[9],Direction[10],Tenant[11],Category[12],Account[13],Subject[14],DestinationPrefix[15],PddInterval[16],UsageInterval[17],Supplier[18],DisconnectCause[19],MediationRunIds[20],RatedAccount[21],RatedSubject[22],CostInterval[23],Triggers[24] @@ -222,7 +222,7 @@ CDRST2,10,10m,,ASR,,,,,,,cgrates.org,call,,,,,,,,,,,, CDRST2,,,,ACD,,,,,,,,,,,,,,,,,,,, ` users = ` -#Tenant[0],UserName[1],AttributeName[2],AttributeValue[3] +#Tenant[0],UserName[1],AttributeName[2],AttributeValue[3],Weight[4] cgrates.org,rif,false,test0,val0,10 cgrates.org,rif,,test1,val1,10 cgrates.org,dan,,another,value,10 @@ -1095,20 +1095,22 @@ func TestLoadDerivedChargers(t *testing.T) { if len(csvr.derivedChargers) != 2 { t.Error("Failed to load derivedChargers: ", csvr.derivedChargers) } - expCharger1 := utils.DerivedChargers{ - &utils.DerivedCharger{RunId: "extra1", RunFilters: "^filteredHeader1/filterValue1/", ReqTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, - TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: utils.META_DEFAULT, - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, - SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, - CategoryField: utils.META_DEFAULT, AccountField: "ivo", SubjectField: "ivo", DestinationField: utils.META_DEFAULT, - SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, - SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, - } + expCharger1 := &utils.DerivedChargers{ + DestinationIds: utils.StringMap{}, + Chargers: []*utils.DerivedCharger{ + &utils.DerivedCharger{RunId: "extra1", RunFilters: "^filteredHeader1/filterValue1/", ReqTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, + TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, + SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, + &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: utils.META_DEFAULT, AccountField: "ivo", SubjectField: "ivo", DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, + SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT, CostField: utils.META_DEFAULT, RatedField: utils.META_DEFAULT}, + }} keyCharger1 := utils.DerivedChargersKey("*out", "cgrates.org", "call", "dan", "dan") if !csvr.derivedChargers[keyCharger1].Equal(expCharger1) { - t.Errorf("Expecting: %+v, received: %+v", expCharger1[0], csvr.derivedChargers[keyCharger1][0]) + t.Errorf("Expecting: %+v, received: %+v", expCharger1.Chargers[0], csvr.derivedChargers[keyCharger1].Chargers[0]) } } func TestLoadCdrStats(t *testing.T) { diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 9897f69a1..cdcca398b 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -472,7 +472,7 @@ func (tps TpDerivedChargers) GetDerivedChargers() (map[string]*utils.TPDerivedCh dcs := make(map[string]*utils.TPDerivedChargers) for _, tpDcMdl := range tps { tpDc := &utils.TPDerivedChargers{TPid: tpDcMdl.Tpid, Loadid: tpDcMdl.Loadid, Direction: tpDcMdl.Direction, Tenant: tpDcMdl.Tenant, Category: tpDcMdl.Category, - Account: tpDcMdl.Account, Subject: tpDcMdl.Subject} + Account: tpDcMdl.Account, Subject: tpDcMdl.Subject, DestinationIds: tpDcMdl.DestinationIds} tag := tpDc.GetDerivedChargesId() if _, hasIt := dcs[tag]; !hasIt { dcs[tag] = tpDc diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 3f16319a0..84b74670a 100644 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -493,9 +493,9 @@ func TestTPDerivedChargersAsExportSlice(t *testing.T) { }, } expectedSlc := [][]string{ - []string{"*out", "cgrates.org", "call", "1001", "1001", + []string{"*out", "cgrates.org", "call", "1001", "1001", "", "derived_run1", "", "^rated", utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, "^1002", utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT}, - []string{"*out", "cgrates.org", "call", "1001", "1001", + []string{"*out", "cgrates.org", "call", "1001", "1001", "", "derived_run2", "", "^rated", utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, "^1002", utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT, utils.META_DEFAULT}, } ms := APItoModelDerivedCharger(dcs) diff --git a/engine/models.go b/engine/models.go index 99aa63ddb..99d8c505b 100644 --- a/engine/models.go +++ b/engine/models.go @@ -255,23 +255,24 @@ type TpDerivedCharger struct { Category string `index:"2" re:"\w+\s*"` Account string `index:"3" re:"\w+\s*"` Subject string `index:"4" re:"\*any\s*|\w+\s*"` - Runid string `index:"5" re:"\w+\s*"` - RunFilters string `index:"6" re:"[~^]*[0-9A-Za-z_/:().+]+\s*"` - ReqTypeField string `index:"7" re:"\*default\s*|[~^*]*[0-9A-Za-z_/:().+]+\s*"` - DirectionField string `index:"8" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - TenantField string `index:"9" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - CategoryField string `index:"10" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - AccountField string `index:"11" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - SubjectField string `index:"12" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - DestinationField string `index:"13" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - SetupTimeField string `index:"14" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - PddField string `index:"15" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - AnswerTimeField string `index:"16" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - UsageField string `index:"17" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - SupplierField string `index:"18" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - DisconnectCauseField string `index:"19" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - RatedField string `index:"20" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` - CostField string `index:"21" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + DestinationIds string `index:"5" re:""` + Runid string `index:"6" re:"\w+\s*"` + RunFilters string `index:"7" re:"[~^]*[0-9A-Za-z_/:().+]+\s*"` + ReqTypeField string `index:"8" re:"\*default\s*|[~^*]*[0-9A-Za-z_/:().+]+\s*"` + DirectionField string `index:"9" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + TenantField string `index:"10" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + CategoryField string `index:"11" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + AccountField string `index:"12" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + SubjectField string `index:"13" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + DestinationField string `index:"14" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + SetupTimeField string `index:"15" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + PddField string `index:"16" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + AnswerTimeField string `index:"17" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + UsageField string `index:"18" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + SupplierField string `index:"19" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + DisconnectCauseField string `index:"20" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + RatedField string `index:"21" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` + CostField string `index:"22" re:"\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*"` CreatedAt time.Time } diff --git a/engine/responder.go b/engine/responder.go index 0b643e278..531df85da 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -294,12 +294,12 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err maxCallDuration := -1.0 attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} - var dcs utils.DerivedChargers - if err := rs.GetDerivedChargers(attrsDC, &dcs); err != nil { + dcs := &utils.DerivedChargers{} + if err := rs.GetDerivedChargers(attrsDC, dcs); err != nil { return err } dcs, _ = dcs.AppendDefaultRun() - for _, dc := range dcs { + for _, dc := range dcs.Chargers { if utils.IsSliceMember([]string{utils.META_RATED, utils.RATED}, ev.GetReqType(dc.ReqTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime continue } @@ -382,8 +382,8 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { } attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} - var dcs utils.DerivedChargers - if err := rs.GetDerivedChargers(attrsDC, &dcs); err != nil { + dcs := &utils.DerivedChargers{} + if err := rs.GetDerivedChargers(attrsDC, dcs); err != nil { rs.getCache().Cache(utils.GET_SESS_RUNS_CACHE_PREFIX+ev.CgrId, &cache2go.CacheItem{ Err: err, }) @@ -391,7 +391,7 @@ func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error { } dcs, _ = dcs.AppendDefaultRun() sesRuns := make([]*SessionRun, 0) - for _, dc := range dcs { + for _, dc := range dcs.Chargers { if !utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, ev.GetReqType(dc.ReqTypeField)) { continue // We only consider prepaid sessions } @@ -426,7 +426,7 @@ func (rs *Responder) GetDerivedChargers(attrs *utils.AttrDerivedChargers, dcs *u if dcsH, err := HandleGetDerivedChargers(ratingStorage, attrs); err != nil { return err } else if dcsH != nil { - *dcs = dcsH + *dcs = *dcsH } return nil } diff --git a/engine/responder_test.go b/engine/responder_test.go index 29b1ee2c6..47e8da081 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -36,8 +36,8 @@ func init() { // Test internal abilites of GetDerivedChargers func TestResponderGetDerivedChargers(t *testing.T) { - cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: utils.META_DEFAULT, DirectionField: "test", TenantField: "test", - CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}} + cfgedDC := &utils.DerivedChargers{DestinationIds: utils.StringMap{}, Chargers: []*utils.DerivedCharger{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: utils.META_DEFAULT, DirectionField: "test", TenantField: "test", + CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}}} rsponder = &Responder{} attrs := &utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "responder_test", Subject: "responder_test"} if err := ratingStorage.SetDerivedChargers(utils.DerivedChargersKey(utils.OUT, utils.ANY, utils.ANY, utils.ANY, utils.ANY), cfgedDC); err != nil { @@ -46,8 +46,8 @@ func TestResponderGetDerivedChargers(t *testing.T) { if err := ratingStorage.CacheRatingPrefixes(utils.DERIVEDCHARGERS_PREFIX); err != nil { t.Error(err) } - var dcs utils.DerivedChargers - if err := rsponder.GetDerivedChargers(attrs, &dcs); err != nil { + dcs := &utils.DerivedChargers{} + if err := rsponder.GetDerivedChargers(attrs, dcs); err != nil { t.Error("Unexpected error", err.Error()) } else if !reflect.DeepEqual(dcs, cfgedDC) { t.Errorf("Expecting: %v, received: %v ", cfgedDC, dcs) @@ -82,14 +82,14 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { t.Error(err) } keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan", "dan") - charger1 := utils.DerivedChargers{ + charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^" + utils.META_PREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^dan", SubjectField: "^dan", DestinationField: "^+49151708707", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^ivo", SubjectField: "^ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "^rif", SubjectField: "^rif", DestinationField: "^+49151708707", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} if err := ratingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { t.Error("Error on setting DerivedChargers", err.Error()) } @@ -106,9 +106,9 @@ func TestResponderGetDerivedMaxSessionTime(t *testing.T) { } else if danStoredAcnt.BalanceMap[utils.VOICE][0].GetValue() != dansAccount.BalanceMap[utils.VOICE][0].GetValue() { t.Error("BalanceValue: ", danStoredAcnt.BalanceMap[utils.VOICE][0].GetValue()) } - var dcs utils.DerivedChargers + dcs := &utils.DerivedChargers{} attrs := &utils.AttrDerivedChargers{Tenant: testTenant, Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} - if err := rsponder.GetDerivedChargers(attrs, &dcs); err != nil { + if err := rsponder.GetDerivedChargers(attrs, dcs); err != nil { t.Error("Unexpected error", err.Error()) } else if !reflect.DeepEqual(dcs, charger1) { t.Errorf("Expecting: %+v, received: %+v ", charger1, dcs) @@ -142,7 +142,7 @@ func TestResponderGetSessionRuns(t *testing.T) { CategoryField: "^0", AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: utils.META_DEFAULT, PddField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT, DisconnectCauseField: utils.META_DEFAULT} - charger1 := utils.DerivedChargers{extra1DC, extra2DC, extra3DC} + charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{extra1DC, extra2DC, extra3DC}} if err := ratingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { t.Error("Error on setting DerivedChargers", err.Error()) } diff --git a/engine/storage_csv.go b/engine/storage_csv.go index 5d9e65ff6..47da6642b 100644 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -417,11 +417,11 @@ func (csvs *CSVStorage) GetTpDerivedChargers(filter *TpDerivedCharger) ([]TpDeri log.Print("bad line in derived chargers csv: ", err) return nil, err } - if tpRate, err := csvLoad(TpDerivedCharger{}, record); err != nil { + if tp, err := csvLoad(TpDerivedCharger{}, record); err != nil { log.Print("error loading derived charger: ", err) return nil, err } else { - dc := tpRate.(TpDerivedCharger) + dc := tp.(TpDerivedCharger) if filter != nil { dc.Tpid = filter.Tpid dc.Loadid = filter.Loadid diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 1490cdcbd..8c51db8ea 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -55,8 +55,8 @@ type RatingStorage interface { SetCdrStats(*CdrStats) error GetCdrStats(string) (*CdrStats, error) GetAllCdrStats() ([]*CdrStats, error) - GetDerivedChargers(string, bool) (utils.DerivedChargers, error) - SetDerivedChargers(string, utils.DerivedChargers) error + GetDerivedChargers(string, bool) (*utils.DerivedChargers, error) + SetDerivedChargers(string, *utils.DerivedChargers) error GetActions(string, bool) (Actions, error) SetActions(string, Actions) error GetSharedGroup(string, bool) (*SharedGroup, error) diff --git a/engine/storage_map.go b/engine/storage_map.go index e040d49b1..077ad11c6 100644 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -722,11 +722,11 @@ func (ms *MapStorage) GetAllActionPlans() (ats map[string]ActionPlans, err error return } -func (ms *MapStorage) GetDerivedChargers(key string, skipCache bool) (dcs utils.DerivedChargers, err error) { +func (ms *MapStorage) GetDerivedChargers(key string, skipCache bool) (dcs *utils.DerivedChargers, err error) { key = utils.DERIVEDCHARGERS_PREFIX + key if !skipCache { if x, err := cache2go.Get(key); err == nil { - return x.(utils.DerivedChargers), nil + return x.(*utils.DerivedChargers), nil } else { return nil, err } @@ -740,8 +740,8 @@ func (ms *MapStorage) GetDerivedChargers(key string, skipCache bool) (dcs utils. return } -func (ms *MapStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers) error { - if len(dcs) == 0 { +func (ms *MapStorage) SetDerivedChargers(key string, dcs *utils.DerivedChargers) error { + if dcs == nil || len(dcs.Chargers) == 0 { delete(ms.dict, utils.DERIVEDCHARGERS_PREFIX+key) cache2go.RemKey(utils.DERIVEDCHARGERS_PREFIX + key) return nil diff --git a/engine/storage_mongo.go b/engine/storage_mongo.go index 1fb6164f5..599799bfc 100644 --- a/engine/storage_mongo.go +++ b/engine/storage_mongo.go @@ -1107,17 +1107,17 @@ func (ms *MongoStorage) GetAllActionPlans() (ats map[string]ActionPlans, err err return } -func (ms *MongoStorage) GetDerivedChargers(key string, skipCache bool) (dcs utils.DerivedChargers, err error) { +func (ms *MongoStorage) GetDerivedChargers(key string, skipCache bool) (dcs *utils.DerivedChargers, err error) { if !skipCache { if x, err := cache2go.Get(utils.DERIVEDCHARGERS_PREFIX + key); err == nil { - return x.(utils.DerivedChargers), nil + return x.(*utils.DerivedChargers), nil } else { return nil, err } } var kv struct { Key string - Value utils.DerivedChargers + Value *utils.DerivedChargers } err = ms.db.C(colDcs).Find(bson.M{"key": key}).One(&kv) if err == nil { @@ -1127,8 +1127,8 @@ func (ms *MongoStorage) GetDerivedChargers(key string, skipCache bool) (dcs util return } -func (ms *MongoStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers) (err error) { - if len(dcs) == 0 { +func (ms *MongoStorage) SetDerivedChargers(key string, dcs *utils.DerivedChargers) (err error) { + if dcs == nil || len(dcs.Chargers) == 0 { cache2go.RemKey(utils.DERIVEDCHARGERS_PREFIX + key) err = ms.db.C(colDcs).Remove(bson.M{"key": key}) if err != mgo.ErrNotFound { @@ -1138,7 +1138,7 @@ func (ms *MongoStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers } _, err = ms.db.C(colDcs).Upsert(bson.M{"key": key}, &struct { Key string - Value utils.DerivedChargers + Value *utils.DerivedChargers }{Key: key, Value: dcs}) return err } diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 2ced135ad..41531cfd3 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -899,11 +899,11 @@ func (rs *RedisStorage) GetAllActionPlans() (ats map[string]ActionPlans, err err return } -func (rs *RedisStorage) GetDerivedChargers(key string, skipCache bool) (dcs utils.DerivedChargers, err error) { +func (rs *RedisStorage) GetDerivedChargers(key string, skipCache bool) (dcs *utils.DerivedChargers, err error) { key = utils.DERIVEDCHARGERS_PREFIX + key if !skipCache { if x, err := cache2go.Get(key); err == nil { - return x.(utils.DerivedChargers), nil + return x.(*utils.DerivedChargers), nil } else { return nil, err } @@ -916,8 +916,8 @@ func (rs *RedisStorage) GetDerivedChargers(key string, skipCache bool) (dcs util return dcs, err } -func (rs *RedisStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers) (err error) { - if len(dcs) == 0 { +func (rs *RedisStorage) SetDerivedChargers(key string, dcs *utils.DerivedChargers) (err error) { + if dcs == nil || len(dcs.Chargers) == 0 { _, err = rs.db.Del(utils.DERIVEDCHARGERS_PREFIX + key) cache2go.RemKey(utils.DERIVEDCHARGERS_PREFIX + key) return err diff --git a/engine/storage_redis_local_test.go b/engine/storage_redis_local_test.go index b3d5e99bc..5a977bf6d 100644 --- a/engine/storage_redis_local_test.go +++ b/engine/storage_redis_local_test.go @@ -56,12 +56,12 @@ func TestSetGetDerivedCharges(t *testing.T) { return } keyCharger1 := utils.ConcatenatedKey("*out", "cgrates.org", "call", "dan", "dan") - charger1 := utils.DerivedChargers{ + charger1 := &utils.DerivedChargers{Chargers: []*utils.DerivedCharger{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - } + }} if err := rds.SetDerivedChargers(keyCharger1, charger1); err != nil { t.Error("Error on setting DerivedChargers", err.Error()) } diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 72d62d059..4ca0a5ee7 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -32,7 +32,7 @@ type TpReader struct { ratingProfiles map[string]*RatingProfile sharedGroups map[string]*SharedGroup lcrs map[string]*LCR - derivedChargers map[string]utils.DerivedChargers + derivedChargers map[string]*utils.DerivedChargers cdrStats map[string]*CdrStats users map[string]*UserProfile aliases map[string]*Alias @@ -62,7 +62,7 @@ func NewTpReader(rs RatingStorage, as AccountingStorage, lr LoadReader, tpid, ti cdrStats: make(map[string]*CdrStats), users: make(map[string]*UserProfile), aliases: make(map[string]*Alias), - derivedChargers: make(map[string]utils.DerivedChargers), + derivedChargers: make(map[string]*utils.DerivedChargers), } //add *any and *asap timing tag (in case of no timings file) tpr.timings[utils.ANY] = &utils.TPTiming{ @@ -893,7 +893,10 @@ func (tpr *TpReader) LoadDerivedChargersFiltered(filter *TpDerivedCharger, save for _, tpDcs := range storDcs { tag := tpDcs.GetDerivedChargersKey() if _, hasIt := tpr.derivedChargers[tag]; !hasIt { - tpr.derivedChargers[tag] = make(utils.DerivedChargers, 0) // Load object map since we use this method also from LoadDerivedChargers + tpr.derivedChargers[tag] = &utils.DerivedChargers{ + DestinationIds: make(utils.StringMap), + Chargers: make([]*utils.DerivedCharger, 0), + } // Load object map since we use this method also from LoadDerivedChargers } for _, tpDc := range tpDcs.DerivedChargers { dc, err := utils.NewDerivedCharger(tpDc.RunId, tpDc.RunFilters, tpDc.ReqTypeField, tpDc.DirectionField, tpDc.TenantField, tpDc.CategoryField, @@ -902,7 +905,8 @@ func (tpr *TpReader) LoadDerivedChargersFiltered(filter *TpDerivedCharger, save if err != nil { return err } - tpr.derivedChargers[tag] = append(tpr.derivedChargers[tag], dc) + tpr.derivedChargers[tag].DestinationIds.Copy(utils.ParseStringMap(tpDcs.DestinationIds)) + tpr.derivedChargers[tag].Chargers = append(tpr.derivedChargers[tag].Chargers, dc) } } if save { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 565367c1f..08d66b902 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -394,6 +394,7 @@ type TPDerivedChargers struct { Category string Account string Subject string + DestinationIds string DerivedChargers []*TPDerivedCharger } @@ -805,7 +806,7 @@ type AttrGetDestination struct { } type AttrDerivedChargers struct { - Direction, Tenant, Category, Account, Subject string + Direction, Tenant, Category, Account, Subject, Destination string } func NewTAFromAccountKey(accountKey string) (*TenantAccount, error) { diff --git a/utils/derivedchargers.go b/utils/derivedchargers.go index e20847b7e..5d9d8def8 100644 --- a/utils/derivedchargers.go +++ b/utils/derivedchargers.go @@ -165,40 +165,6 @@ type DerivedCharger struct { rsrRatedField *RSRField } -func DerivedChargersKey(direction, tenant, category, account, subject string) string { - return ConcatenatedKey(direction, tenant, category, account, subject) -} - -type DerivedChargers []*DerivedCharger - -// Precheck that RunId is unique -func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) { - if dc.RunId == DEFAULT_RUNID { - return nil, errors.New("Reserved RunId") - } - for _, dcLocal := range dcs { - if dcLocal.RunId == dc.RunId { - return nil, errors.New("Duplicated RunId") - } - } - return append(dcs, dc), nil -} - -func (dcs DerivedChargers) AppendDefaultRun() (DerivedChargers, error) { - dcDf, _ := NewDerivedCharger(DEFAULT_RUNID, "", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, - META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT) - return append(dcs, dcDf), nil -} - -func (dcs DerivedChargers) Equal(other DerivedChargers) bool { - for i, dc := range dcs { - if !dc.Equal(other[i]) { - return false - } - } - return true -} - func (dc *DerivedCharger) Equal(other *DerivedCharger) bool { return dc.RunId == other.RunId && dc.RunFilters == other.RunFilters && @@ -218,3 +184,43 @@ func (dc *DerivedCharger) Equal(other *DerivedCharger) bool { dc.CostField == other.CostField && dc.RatedField == other.RatedField } + +func DerivedChargersKey(direction, tenant, category, account, subject string) string { + return ConcatenatedKey(direction, tenant, category, account, subject) +} + +type DerivedChargers struct { + DestinationIds StringMap + Chargers []*DerivedCharger +} + +// Precheck that RunId is unique +func (dcs *DerivedChargers) Append(dc *DerivedCharger) (*DerivedChargers, error) { + if dc.RunId == DEFAULT_RUNID { + return nil, errors.New("Reserved RunId") + } + for _, dcLocal := range dcs.Chargers { + if dcLocal.RunId == dc.RunId { + return nil, errors.New("Duplicated RunId") + } + } + dcs.Chargers = append(dcs.Chargers, dc) + return dcs, nil +} + +func (dcs *DerivedChargers) AppendDefaultRun() (*DerivedChargers, error) { + dcDf, _ := NewDerivedCharger(DEFAULT_RUNID, "", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, + META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT) + dcs.Chargers = append(dcs.Chargers, dcDf) + return dcs, nil +} + +func (dcs *DerivedChargers) Equal(other *DerivedChargers) bool { + dcs.DestinationIds.Equal(other.DestinationIds) + for i, dc := range dcs.Chargers { + if !dc.Equal(other.Chargers[i]) { + return false + } + } + return true +} diff --git a/utils/derivedchargers_test.go b/utils/derivedchargers_test.go index 24f621177..4a2fffe31 100644 --- a/utils/derivedchargers_test.go +++ b/utils/derivedchargers_test.go @@ -25,19 +25,20 @@ import ( func TestAppendDerivedChargers(t *testing.T) { var err error - dcs := make(DerivedChargers, 0) + + dcs := &DerivedChargers{Chargers: make([]*DerivedCharger, 0)} if _, err := dcs.Append(&DerivedCharger{RunId: DEFAULT_RUNID}); err == nil { t.Error("Failed to detect using of the default runid") } if dcs, err = dcs.Append(&DerivedCharger{RunId: "FIRST_RUNID"}); err != nil { t.Error("Failed to add runid") - } else if len(dcs) != 1 { - t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs)) + } else if len(dcs.Chargers) != 1 { + t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs.Chargers)) } if dcs, err = dcs.Append(&DerivedCharger{RunId: "SECOND_RUNID"}); err != nil { t.Error("Failed to add runid") - } else if len(dcs) != 2 { - t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs)) + } else if len(dcs.Chargers) != 2 { + t.Error("Unexpected number of items inside DerivedChargers configuration", len(dcs.Chargers)) } if _, err := dcs.Append(&DerivedCharger{RunId: "SECOND_RUNID"}); err == nil { t.Error("Failed to detect duplicate runid") @@ -135,25 +136,26 @@ func TestDerivedChargersKey(t *testing.T) { } func TestAppendDefaultRun(t *testing.T) { - var dc1 DerivedChargers + dc1 := &DerivedChargers{} dcDf := &DerivedCharger{RunId: DEFAULT_RUNID, RunFilters: "", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: META_DEFAULT, SubjectField: META_DEFAULT, DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, SupplierField: META_DEFAULT, DisconnectCauseField: META_DEFAULT, CostField: META_DEFAULT, RatedField: META_DEFAULT} - eDc1 := DerivedChargers{dcDf} + eDc1 := &DerivedChargers{Chargers: []*DerivedCharger{dcDf}} if dc1, _ = dc1.AppendDefaultRun(); !reflect.DeepEqual(dc1, eDc1) { - t.Errorf("Expecting: %+v, received: %+v", eDc1[0], dc1[0]) + t.Errorf("Expecting: %+v, received: %+v", eDc1.Chargers[0], dc1.Chargers[0]) } - dc2 := DerivedChargers{ + dc2 := &DerivedChargers{Chargers: []*DerivedCharger{ &DerivedCharger{RunId: "extra1", RunFilters: "", ReqTypeField: "reqtype2", DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, DisconnectCauseField: META_DEFAULT}, &DerivedCharger{RunId: "extra2", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: "ivo", SubjectField: "ivo", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, PddField: META_DEFAULT, AnswerTimeField: META_DEFAULT, - UsageField: META_DEFAULT, SupplierField: META_DEFAULT, DisconnectCauseField: META_DEFAULT}, + UsageField: META_DEFAULT, SupplierField: META_DEFAULT, DisconnectCauseField: META_DEFAULT}}, } - eDc2 := append(dc2, dcDf) + eDc2 := &DerivedChargers{} + eDc2.Chargers = append(dc2.Chargers, dcDf) if dc2, _ = dc2.AppendDefaultRun(); !reflect.DeepEqual(dc2, eDc2) { - t.Errorf("Expecting: %+v, received: %+v", eDc2, dc2) + t.Errorf("Expecting: %+v, received: %+v", eDc2.Chargers, dc2.Chargers) } } diff --git a/utils/map.go b/utils/map.go index 22a4fde6c..5a71ca506 100644 --- a/utils/map.go +++ b/utils/map.go @@ -127,12 +127,18 @@ func (sm StringMap) Slice() []string { return result } +func (sm StringMap) Copy(o StringMap) { + for k, v := range o { + sm[k] = v + } +} + func (sm StringMap) String() string { return strings.Join(sm.Slice(), INFIELD_SEP) } func (sm StringMap) GetOne() string { - for key := range sm{ + for key := range sm { return key } return ""