/* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package agents import ( "bufio" "bytes" "fmt" "net/http" "reflect" "strings" "testing" "time" "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" "github.com/cgrates/go-diameter/diam" "github.com/cgrates/go-diameter/diam/avp" "github.com/cgrates/go-diameter/diam/datatype" "github.com/cgrates/radigo" "github.com/google/go-cmp/cmp" ) func TestAgReqSetFields(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String())) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.MetaVoice) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, "1001") agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, "1002") agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.MetaPrepaid) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Usage, PathSlice: []string{utils.Usage}}, 3*time.Minute) cgrRply := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ utils.CapAttributes: {Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "PaypalAccount": utils.NewLeafNode("cgrates@paypal.com"), }}, utils.CapMaxUsage: utils.NewLeafNode(120 * time.Second), utils.Error: utils.NewLeafNode(""), }, } agReq.CGRReply = cgrRply tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaRep + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaRep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Destination", Path: utils.MetaRep + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, {Tag: "RequestedUsageVoice", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*voice"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_seconds}", utils.InfieldSep)}, {Tag: "RequestedUsageData", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*data"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_nanoseconds}", utils.InfieldSep)}, {Tag: "RequestedUsageSMS", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*sms"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_nanoseconds}", utils.InfieldSep)}, {Tag: "AttrPaypalAccount", Path: utils.MetaRep + utils.NestingSep + "PaypalAccount", Type: utils.MetaVariable, Filters: []string{"*empty:~*cgrep.Error:"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.Attributes.PaypalAccount", utils.InfieldSep)}, {Tag: "MaxUsage", Path: utils.MetaRep + utils.NestingSep + "MaxUsage", Type: utils.MetaVariable, Filters: []string{"*empty:~*cgrep.Error:"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.MaxUsage{*duration_seconds}", utils.InfieldSep)}, {Tag: "Error", Path: utils.MetaRep + utils.NestingSep + "Error", Type: utils.MetaVariable, Filters: []string{"*rsr:~*cgrep.Error:!^$"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.Error", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := utils.NewOrderedNavigableMap() eMp.SetAsSlice(&utils.FullPath{Path: utils.Tenant, PathSlice: []string{utils.Tenant}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.SetAsSlice(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.SetAsSlice(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "RequestedUsage", PathSlice: []string{"RequestedUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "180"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "PaypalAccount", PathSlice: []string{"PaypalAccount"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates@paypal.com"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "MaxUsage", PathSlice: []string{"MaxUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "120"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.Reply, eMp) { t.Log(utils.ToJSON(eMp.GetOrder())) t.Log(utils.ToJSON(agReq.Reply.GetOrder())) t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.Reply) } } func TestAgReqSetFieldsComp(t *testing.T) { req := map[string]any{ utils.AccountField: 1009, utils.Tenant: "cgrates.org", } cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) ar := NewAgentRequest(utils.MapStorage(req), nil, nil, nil, nil, config.NewRSRParsersMustCompile("", utils.NestingSep), "cgrates.org", "", engine.NewFilterS(cfg, nil, dm), map[string]utils.DataProvider{utils.MetaHdr: utils.MapStorage(req), utils.MetaTrl: utils.MapStorage(req)}) input := []*config.FCTemplate{} if err := ar.SetFields(input); err != nil { t.Error(err) } // tplFld.Type == utils.MetaNone input = []*config.FCTemplate{{Type: utils.MetaNone}} if err := ar.SetFields(input); err != nil { t.Error(err) } // unsupported type: <> input = []*config.FCTemplate{{Blocker: true}} if err := ar.SetFields(input); err == nil || err.Error() != "unsupported type: <>" { t.Error(err) } // case utils.MetaVars input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaVars), Tag: fmt.Sprintf("%s.Account", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Errorf("Expecting NM items<%T>", val) } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // case utils.MetaCgreq input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaCgreq), Tag: fmt.Sprintf("%s.Account", utils.MetaCgreq), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.CGRRequest.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // case utils.MetaCgrep input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaCgrep), Tag: fmt.Sprintf("%s.Account", utils.MetaCgrep), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.CGRReply.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // case utils.MetaRep input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaRep), Tag: fmt.Sprintf("%s.Account", utils.MetaRep), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Reply.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // case utils.MetaDiamreq input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaDiamreq), Tag: fmt.Sprintf("%s.Account", utils.MetaDiamreq), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.diamreq.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // case utils.MetaRadDAReq input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaRadDAReq), Tag: fmt.Sprintf("%s.Account", utils.MetaRadDAReq), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.radDAReq.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } //MetaComposed input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.AccountID", utils.MetaVars), Tag: fmt.Sprintf("%s.AccountID", utils.MetaVars), Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Tenant", utils.InfieldSep), }, { Path: fmt.Sprintf("%s.AccountID", utils.MetaVars), Tag: fmt.Sprintf("%s.AccountID", utils.MetaVars), Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile(":", utils.InfieldSep), }, { Path: fmt.Sprintf("%s.AccountID", utils.MetaVars), Tag: fmt.Sprintf("%s.AccountID", utils.MetaVars), Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), }, } for _, v := range input { v.ComputePath() } if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"AccountID"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "cgrates.org:1009" { t.Error("Expecting 'cgrates.org:1009', received: ", nm[0].Value.Data) } // MetaConstant input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaVars), Tag: fmt.Sprintf("%s.Account", utils.MetaVars), Type: utils.MetaConstant, Value: config.NewRSRParsersMustCompile("2020", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"Account"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "2020" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // Filters input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.AccountID", utils.MetaVars), Tag: fmt.Sprintf("%s.AccountID", utils.MetaVars), Filters: []string{utils.MetaString + ":~" + utils.MetaVars + ".Account:1003"}, Type: utils.MetaConstant, Value: config.NewRSRParsersMustCompile("2021", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"AccountID"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item ", utils.ToJSON(nm)) } else if nm[0].Value.Data != "cgrates.org:1009" { t.Error("Expecting 'cgrates.org:1009', received: ", nm[0].Value.Data) } input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account", utils.MetaVars), Tag: fmt.Sprintf("%s.Account", utils.MetaVars), Filters: []string{"Not really a filter"}, Type: utils.MetaConstant, Value: config.NewRSRParsersMustCompile("2021", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err == nil || err.Error() != "NOT_FOUND:Not really a filter" { t.Errorf("Expecting: 'NOT_FOUND:Not really a filter', received: %+v", err) } // Blocker: true input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Name", utils.MetaVars), Tag: fmt.Sprintf("%s.Name", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Account", utils.InfieldSep), Blocker: true, }, { Path: fmt.Sprintf("%s.Name", utils.MetaVars), Tag: fmt.Sprintf("%s.Name", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("1005", utils.InfieldSep), }, } for _, v := range input { v.ComputePath() } if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"Name"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } // ErrNotFound input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Test", utils.MetaVars), Tag: fmt.Sprintf("%s.Test", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Test", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if _, err := ar.Vars.FieldAsInterface([]string{"Test"}); err == nil || err != utils.ErrNotFound { t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err) } input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Test", utils.MetaVars), Tag: fmt.Sprintf("%s.Test", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaReq+".Test", utils.InfieldSep), Mandatory: true, }, } input[0].ComputePath() if err := ar.SetFields(input); err == nil || err.Error() != "NOT_FOUND:"+utils.MetaVars+".Test" { t.Errorf("Expecting: %+v, received: %+v", "NOT_FOUND:"+utils.MetaVars+".Test", err) } //Not found input = []*config.FCTemplate{ { Path: "wrong", Tag: "wrong", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*req.Account", utils.InfieldSep), Mandatory: true, }, } input[0].ComputePath() if err := ar.SetFields(input); err == nil || err.Error() != "unsupported field prefix: when set field" { t.Errorf("Expecting: %+v, received: %+v", "unsupported field prefix: when set field", err) } // MetaHdr/MetaTrl input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account4", utils.MetaVars), Tag: fmt.Sprintf("%s.Account4", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaHdr+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"Account4"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } input = []*config.FCTemplate{ { Path: fmt.Sprintf("%s.Account5", utils.MetaVars), Tag: fmt.Sprintf("%s.Account5", utils.MetaVars), Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~"+utils.MetaTrl+".Account", utils.InfieldSep), }, } input[0].ComputePath() if err := ar.SetFields(input); err != nil { t.Error(err) } else if val, err := ar.Vars.FieldAsInterface([]string{"Account5"}); err != nil { t.Error(err) } else if nm, ok := val.([]*utils.DataNode); !ok { t.Error("Expecting NM items") } else if len(nm) != 1 { t.Error("Expecting one item") } else if nm[0].Value.Data != "1009" { t.Error("Expecting 1009, received: ", nm[0].Value.Data) } } func TestAgReqMaxCost(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.CapMaxUsage, PathSlice: []string{utils.CapMaxUsage}}, utils.NewLeafNode("120s")) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ utils.CapMaxUsage: utils.NewLeafNode(120 * time.Second), }} tplFlds := []*config.FCTemplate{ {Tag: "MaxUsage", Path: utils.MetaRep + utils.NestingSep + "MaxUsage", Type: utils.MetaVariable, Filters: []string{"*rsr:~*cgrep.MaxUsage:>0s"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.MaxUsage{*duration_seconds}", utils.InfieldSep)}, } tplFlds[0].ComputePath() eMp := utils.NewOrderedNavigableMap() eMp.SetAsSlice(&utils.FullPath{Path: "MaxUsage", PathSlice: []string{"MaxUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "120"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.Reply, eMp) { t.Log(utils.ToJSON(eMp.GetOrder())) t.Log(utils.ToJSON(agReq.Reply.GetOrder())) t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.Reply) } } func TestAgReqParseFieldDiameter(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "MandatoryFalse", Path: "MandatoryFalse", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryFalse", utils.InfieldSep), Mandatory: false}, {Tag: "MandatoryTrue", Path: "MandatoryTrue", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryTrue", utils.InfieldSep), Mandatory: true}, {Tag: "Session-Id", Filters: []string{}, Path: "Session-Id", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } for _, v := range tplFlds { v.ComputePath() } expected := "" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } if _, err := agReq.ParseField(tplFlds[1]); err == nil || err.Error() != "Empty source value for fieldID: " { t.Error(err) } expected = "simuhuawei;1449573472;00002" if out, err := agReq.ParseField(tplFlds[2]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } } func TestAgReqParseFieldRadius(t *testing.T) { //creater radius message pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org") if err := pkt.AddAVPWithName("User-Name", "flopsy", ""); err != nil { t.Error(err) } if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil { t.Error(err) } //create radiusDataProvider dP := newRADataProvider(pkt) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "MandatoryFalse", Path: "MandatoryFalse", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryFalse", utils.InfieldSep), Mandatory: false}, {Tag: "MandatoryTrue", Path: "MandatoryTrue", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryTrue", utils.InfieldSep), Mandatory: true}, } for _, v := range tplFlds { v.ComputePath() } expected := "" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } if _, err := agReq.ParseField(tplFlds[1]); err == nil || err.Error() != "Empty source value for fieldID: " { t.Error(err) } } func TestAgReqParseFieldHttpUrl(t *testing.T) { //creater radius message br := bufio.NewReader(strings.NewReader(`GET /cdr?request_type=MOSMS_CDR×tamp=2008-08-15%2017:49:21&message_date=2008-08-15%2017:49:21&transactionid=100744&CDR_ID=123456&carrierid=1&mcc=222&mnc=10&imsi=235180000000000&msisdn=%2B4977000000000&destination=%2B497700000001&message_status=0&IOT=0&service_id=1 HTTP/1.1 Host: api.cgrates.org `)) req, err := http.ReadRequest(br) if err != nil { t.Error(err) } //create radiusDataProvider dP, _ := newHTTPUrlDP(req) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "MandatoryFalse", Path: "MandatoryFalse", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryFalse", utils.InfieldSep), Mandatory: false}, {Tag: "MandatoryTrue", Path: "MandatoryTrue", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryTrue", utils.InfieldSep), Mandatory: true}, } expected := "" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } if _, err := agReq.ParseField(tplFlds[1]); err == nil || err.Error() != "Empty source value for fieldID: " { t.Error(err) } } func TestAgReqParseFieldHttpXml(t *testing.T) { //creater radius message body := ` 2005-08-26T14:16:42 2005-08-26T14:16:56 2005-08-26T14:17:34 My Call Reference 386 sampleusername 1 Conecto LLC US$0.21 yes no US$0.13 44 +441624828505 Isle of Man 38 US$0.0200 US$0.0140 US$0.0130 US$0.0082 +44 7624 494075 Isle of Man 37 US$0.2700 US$0.1890 US$0.1880 US$0.1159 ` req, err := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer([]byte(body))) if err != nil { t.Error(err) } //create radiusDataProvider dP, _ := newHTTPXmlDP(req) cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "MandatoryFalse", Path: "MandatoryFalse", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryFalse", utils.InfieldSep), Mandatory: false}, {Tag: "MandatoryTrue", Path: "MandatoryTrue", Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*req.MandatoryTrue", utils.InfieldSep), Mandatory: true}, } expected := "" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } if _, err := agReq.ParseField(tplFlds[1]); err == nil || err.Error() != "Empty source value for fieldID: " { t.Error(err) } } func TestAgReqEmptyFilter(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String())) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Filters: []string{}, Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Filters: []string{}, Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Destination", Filters: []string{}, Path: utils.MetaCgrep + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{utils.Destination}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } func TestAgReqMetaExponent(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: "Value", PathSlice: []string{"Value"}}, utils.NewLeafNode("2")) agReq.CGRRequest.Set(&utils.FullPath{Path: "Exponent", PathSlice: []string{"Exponent"}}, utils.NewLeafNode("2")) tplFlds := []*config.FCTemplate{ {Tag: "TestExpo", Filters: []string{}, Path: utils.MetaCgrep + utils.NestingSep + "TestExpo", Type: utils.MetaValueExponent, Value: config.NewRSRParsersMustCompile("~*cgreq.Value;~*cgreq.Exponent", utils.InfieldSep)}, } tplFlds[0].ComputePath() eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{"TestExpo"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "200"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } func TestAgReqFieldAsNone(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Type: utils.MetaNone, Blocker: true}, {Tag: "Destination", Path: utils.MetaCgrep + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } func TestAgReqFieldAsNone2(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Type: utils.MetaNone}, {Tag: "Destination", Path: utils.MetaCgrep + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{utils.Destination}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } func TestAgReqSetField2(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Destination", Path: utils.MetaCgrep + utils.NestingSep + utils.Destination, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, {Tag: "Usage", Path: utils.MetaCgrep + utils.NestingSep + utils.Usage, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("30s", utils.InfieldSep)}, {Tag: "CalculatedUsage", Path: utils.MetaCgrep + utils.NestingSep + "CalculatedUsage", Type: "*difference", Value: config.NewRSRParsersMustCompile("~*cgreq.AnswerTime;~*cgrep.Usage", utils.InfieldSep), }, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{utils.Destination}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) eMp.Set([]string{"Usage"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "30s"}}}) eMp.Set([]string{"CalculatedUsage"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC)}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } func TestAgReqFieldAsInterface(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest = utils.NewOrderedNavigableMap() agReq.CGRRequest.Set(&utils.FullPath{ Path: utils.Usage, PathSlice: []string{utils.Usage}, }, &utils.DataNode{ Type: utils.NMSliceType, Slice: []*utils.DataNode{ { Type: utils.NMDataType, Value: &utils.DataLeaf{ Data: 3 * time.Minute, }, }, }, }) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, &utils.DataNode{Type: utils.NMSliceType, Slice: []*utils.DataNode{{Type: utils.NMDataType, Value: &utils.DataLeaf{Data: utils.MetaVoice}}}}) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) path := []string{utils.MetaCgreq, utils.Usage} var expVal any expVal = 3 * time.Minute if rply, err := agReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(rply, expVal) { t.Errorf("Expected %v , received: %v", utils.ToJSON(expVal), utils.ToJSON(rply)) } path = []string{utils.MetaCgreq, utils.ToR} expVal = utils.MetaVoice if rply, err := agReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(rply, expVal) { t.Errorf("Expected %v , received: %v", utils.ToJSON(expVal), utils.ToJSON(rply)) } path = []string{utils.MetaCgreq, utils.AccountField} expVal = "1001" if rply, err := agReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(rply, expVal) { t.Errorf("Expected %v , received: %v", utils.ToJSON(expVal), utils.ToJSON(rply)) } path = []string{utils.MetaCgreq, utils.Destination} expVal = "1002" if rply, err := agReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(rply, expVal) { t.Errorf("Expected %v , received: %v", utils.ToJSON(expVal), utils.ToJSON(rply)) } path = []string{utils.MetaTenant} expVal = "cgrates.org" if rply, err := agReq.FieldAsInterface(path); err != nil { t.Error() } else if !reflect.DeepEqual(rply, expVal) { t.Errorf("Expected %v , received: %v", utils.ToJSON(expVal), utils.ToJSON(rply)) } } func TestAgReqFieldAsInterfaceForOneFldPathCgrReq(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) aqReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) aqReq.CGRRequest.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.NewLeafNode("CGRATES_ID1")) aqReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1002")) aqReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode(time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC))) path := []string{utils.MetaCgreq} expVal := utils.NewOrderedNavigableMap() expVal.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, &utils.DataLeaf{Data: "CGRATES_ID1"}) expVal.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, &utils.DataLeaf{Data: "1002"}) expVal.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, &utils.DataLeaf{Data: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC)}) if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expVal, rply) { t.Errorf("Expected %+v, received %+v", expVal, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathVars(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) dN := &utils.DataNode{ Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Name": utils.NewLeafNode("1001"), "ExtraFields": { Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Usage": utils.NewLeafNode("20m"), }, }, }, } aqReq := NewAgentRequest(nil, dN, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) path := []string{utils.MetaVars} if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(dN, rply) { t.Errorf("Expected %+v, received %+v", dN, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathCgrReply(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) dN := &utils.DataNode{ Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Name": utils.NewLeafNode("1001"), "ExtraFields": { Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Usage": utils.NewLeafNode("20m"), }, }, }, } aqReq := NewAgentRequest(nil, nil, dN, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) path := []string{utils.MetaCgrep} if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(dN, rply) { t.Errorf("Expected %+v, received %+v", dN, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathTmp(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) dN := &utils.DataNode{ Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Name": utils.NewLeafNode("1001"), "ExtraFields": { Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "Usage": utils.NewLeafNode("20m"), }, }, }, } aqReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) aqReq.tmp = dN path := []string{utils.MetaTmp} if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(dN, rply) { t.Errorf("Expected %+v, received %+v", dN, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathReq(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) dP := &utils.MapStorage{ utils.CGRID: "CGRATES_ID1", utils.AccountField: "1002", utils.AnswerTime: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC), } aqReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) path := []string{utils.MetaReq} expVal := &utils.MapStorage{ utils.CGRID: "CGRATES_ID1", utils.AccountField: "1002", utils.AnswerTime: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC), } if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expVal, rply) { t.Errorf("Expected %+v, received %+v", expVal, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathDiamReq(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) aqReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) aqReq.diamreq.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.NewLeafNode("CGRATES_ID1")) aqReq.diamreq.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1002")) aqReq.diamreq.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode(time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC))) path := []string{utils.MetaDiamreq} expVal := utils.NewOrderedNavigableMap() expVal.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, &utils.DataLeaf{Data: "CGRATES_ID1"}) expVal.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, &utils.DataLeaf{Data: "1002"}) expVal.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, &utils.DataLeaf{Data: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC)}) if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expVal, rply) { t.Errorf("Expected %+v, received %+v", expVal, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathReply(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) aqReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) aqReq.Reply.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.NewLeafNode("CGRATES_ID1")) aqReq.Reply.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1002")) aqReq.Reply.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode(time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC))) path := []string{utils.MetaRep} expVal := utils.NewOrderedNavigableMap() expVal.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, &utils.DataLeaf{Data: "CGRATES_ID1"}) expVal.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, &utils.DataLeaf{Data: "1002"}) expVal.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, &utils.DataLeaf{Data: time.Date(2013, 12, 30, 14, 59, 31, 0, time.UTC)}) if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expVal, rply) { t.Errorf("Expected %+v, received %+v", expVal, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathOpts(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) opts := utils.MapStorage{ utils.AccountField: "1002", utils.Usage: "30m", } aqReq := NewAgentRequest(nil, nil, nil, nil, opts, nil, "cgrates.org", utils.EmptyString, filterS, nil) path := []string{utils.MetaOpts} expOpts := utils.MapStorage{ utils.AccountField: "1002", utils.Usage: "30m", } if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expOpts, rply) { t.Errorf("Expected %+v, received %+v", expOpts, rply) } } func TestAgReqFieldAsInterfaceForOneFldPathCfg(t *testing.T) { tmp := config.CgrConfig() cfg := config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) aqReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", utils.EmptyString, filterS, nil) path := []string{utils.MetaCfg} expVal := config.CgrConfig().GetDataProvider() if rply, err := aqReq.FieldAsInterface(path); err != nil { t.Error(err) } else if !reflect.DeepEqual(expVal, rply) { t.Errorf("Expected %+v \n, received %+v", expVal, rply) } config.SetCgrConfig(tmp) } func TestAgReqNewARWithCGRRplyAndRply(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) rply := utils.NewOrderedNavigableMap() rply.Set(&utils.FullPath{ Path: "FirstLevel.SecondLevel.Fld1", PathSlice: []string{"FirstLevel", "SecondLevel", "Fld1"}}, utils.NewLeafNode("Val1")) cgrRply := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ utils.CapAttributes: {Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "PaypalAccount": utils.NewLeafNode("cgrates@paypal.com"), }}, utils.CapMaxUsage: utils.NewLeafNode(120 * time.Second), utils.Error: utils.NewLeafNode(""), }} agReq := NewAgentRequest(nil, nil, cgrRply, rply, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Fld1", Path: utils.MetaCgreq + utils.NestingSep + "Fld1", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*rep.FirstLevel.SecondLevel.Fld1", utils.InfieldSep)}, {Tag: "Fld2", Path: utils.MetaCgreq + utils.NestingSep + "Fld2", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgrep.Attributes.PaypalAccount", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := utils.NewOrderedNavigableMap() eMp.SetAsSlice(&utils.FullPath{Path: "Fld1", PathSlice: []string{"Fld1"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "Val1"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "Fld2", PathSlice: []string{"Fld2"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates@paypal.com"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRRequest, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRRequest) } } func TestAgReqSetCGRReplyWithError(t *testing.T) { cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) rply := utils.NewOrderedNavigableMap() rply.Set(&utils.FullPath{ Path: "FirstLevel.SecondLevel.Fld1", PathSlice: []string{"FirstLevel", "SecondLevel", "Fld1"}}, utils.NewLeafNode("Val1")) agReq := NewAgentRequest(nil, nil, nil, rply, nil, nil, "cgrates.org", "", filterS, nil) agReq.setCGRReply(nil, utils.ErrNotFound) tplFlds := []*config.FCTemplate{ {Tag: "Fld1", Path: utils.MetaCgreq + utils.NestingSep + "Fld1", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*rep.FirstLevel.SecondLevel.Fld1", utils.InfieldSep)}, {Tag: "Fld2", Path: utils.MetaCgreq + utils.NestingSep + "Fld2", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgrep.Attributes.PaypalAccount", utils.InfieldSep), Mandatory: true}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err == nil || err.Error() != "NOT_FOUND:Fld2" { t.Error(err) } } type myEv map[string]*utils.DataNode func (ev myEv) AsNavigableMap() map[string]*utils.DataNode { return ev } func TestAgReqSetCGRReplyWithoutError(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) rply := utils.NewOrderedNavigableMap() rply.Set(&utils.FullPath{ Path: "FirstLevel.SecondLevel.Fld1", PathSlice: []string{"FirstLevel", "SecondLevel", "Fld1"}}, utils.NewLeafNode("Val1")) myEv := myEv{ utils.CapAttributes: &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "PaypalAccount": utils.NewLeafNode("cgrates@paypal.com"), }}, utils.CapMaxUsage: utils.NewLeafNode(120 * time.Second), utils.Error: utils.NewLeafNode(""), } agReq := NewAgentRequest(nil, nil, nil, rply, nil, nil, "cgrates.org", "", filterS, nil) agReq.setCGRReply(myEv, nil) tplFlds := []*config.FCTemplate{ {Tag: "Fld1", Path: utils.MetaCgreq + utils.NestingSep + "Fld1", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*rep.FirstLevel.SecondLevel.Fld1", utils.InfieldSep)}, {Tag: "Fld2", Path: utils.MetaCgreq + utils.NestingSep + "Fld2", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgrep.Attributes.PaypalAccount", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := utils.NewOrderedNavigableMap() eMp.SetAsSlice(&utils.FullPath{Path: "Fld1", PathSlice: []string{"Fld1"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "Val1"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "Fld2", PathSlice: []string{"Fld2"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates@paypal.com"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRRequest, eMp) { t.Log(utils.ToJSON(eMp.GetOrder())) t.Log(utils.ToJSON(agReq.CGRRequest.GetOrder())) t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRRequest) } } func TestAgReqParseFieldMetaCCUsage(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "CCUsage", Filters: []string{}, Path: "CCUsage", Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } tplFlds[0].ComputePath() if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid arguments <[{"Rules":"~*req.Session-Id"}]> to *cc_usage` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "CCUsage", Filters: []string{}, Path: "CCUsage", Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("~*req.Session-Id;12s;12s", utils.InfieldSep), Mandatory: true}, } tplFlds[0].ComputePath() if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid requestNumber to *cc_usage` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "CCUsage", Filters: []string{}, Path: "CCUsage", Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("10;~*req.Session-Id;12s", utils.InfieldSep), Mandatory: true}, } tplFlds[0].ComputePath() if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid usedCCTime to *cc_usage` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "CCUsage", Filters: []string{}, Path: "CCUsage", Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("10;12s;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } tplFlds[0].ComputePath() if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid debitInterval to *cc_usage` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "CCUsage", Filters: []string{}, Path: "CCUsage", Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("3;10s;5s", utils.InfieldSep), Mandatory: true}, } tplFlds[0].ComputePath() //5s*2 + 10s expected := 20 * time.Second if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } } func TestAgReqParseFieldMetaUsageDifference(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Usage", Filters: []string{}, Path: "Usage", Type: utils.MetaUsageDifference, Value: config.NewRSRParsersMustCompile("~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid arguments <[{"Rules":"~*req.Session-Id"}]> to *usage_difference` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Usage", Filters: []string{}, Path: "Usage", Type: utils.MetaUsageDifference, Value: config.NewRSRParsersMustCompile("1560325161;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `Unsupported time format` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Usage", Filters: []string{}, Path: "Usage", Type: utils.MetaUsageDifference, Value: config.NewRSRParsersMustCompile("~*req.Session-Id;1560325161", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `Unsupported time format` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Usage", Filters: []string{}, Path: "Usage", Type: utils.MetaUsageDifference, Value: config.NewRSRParsersMustCompile("1560325161;1560325151", utils.InfieldSep), Mandatory: true}, } expected := "10s" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, received: <%+v>", expected, out) } } func TestAgReqParseFieldMetaSum(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Sum", Filters: []string{}, Path: "Sum", Type: utils.MetaSum, Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Sum", Filters: []string{}, Path: "Sum", Type: utils.MetaSum, Value: config.NewRSRParsersMustCompile("15;15", utils.InfieldSep), Mandatory: true}, } expected := int64(30) if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out) } } func TestAgReqParseFieldMetaDifference(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(idb, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Diff", Filters: []string{}, Path: "Diff", Type: utils.MetaDifference, Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Diff", Filters: []string{}, Path: "Diff", Type: utils.MetaDifference, Value: config.NewRSRParsersMustCompile("15;12;2", utils.InfieldSep), Mandatory: true}, } expected := int64(1) if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out) } } func TestAgReqParseFieldMetaMultiply(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Multiply", Filters: []string{}, Path: "Multiply", Type: utils.MetaMultiply, Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Multiply", Filters: []string{}, Path: "Multiply", Type: utils.MetaMultiply, Value: config.NewRSRParsersMustCompile("15;15", utils.InfieldSep), Mandatory: true}, } expected := int64(225) if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out) } } func TestAgReqParseFieldMetaDivide(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Divide", Filters: []string{}, Path: "Divide", Type: utils.MetaDivide, Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "Divide", Filters: []string{}, Path: "Divide", Type: utils.MetaDivide, Value: config.NewRSRParsersMustCompile("15;3", utils.InfieldSep), Mandatory: true}, } expected := int64(5) if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out) } } func TestAgReqParseFieldMetaValueExponent(t *testing.T) { //creater diameter message m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002")) m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)), }}) //create diameterDataProvider dP := newDADataProvider(nil, m) cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(dP, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "ValExp", Filters: []string{}, Path: "ValExp", Type: utils.MetaValueExponent, Value: config.NewRSRParsersMustCompile("~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid arguments <[{"Rules":"~*req.Session-Id"}]> to *value_exponent` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "ValExp", Filters: []string{}, Path: "ValExp", Type: utils.MetaValueExponent, Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `strconv.Atoi: parsing "simuhuawei;1449573472;00002": invalid syntax` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "ValExp", Filters: []string{}, Path: "ValExp", Type: utils.MetaValueExponent, Value: config.NewRSRParsersMustCompile("~*req.Session-Id;15", utils.InfieldSep), Mandatory: true}, } if _, err := agReq.ParseField(tplFlds[0]); err == nil || err.Error() != `invalid value to *value_exponent` { t.Error(err) } tplFlds = []*config.FCTemplate{ {Tag: "ValExp", Filters: []string{}, Path: "ValExp", Type: utils.MetaValueExponent, Value: config.NewRSRParsersMustCompile("2;3", utils.InfieldSep), Mandatory: true}, } expected := "2000" if out, err := agReq.ParseField(tplFlds[0]); err != nil { t.Error(err) } else if !reflect.DeepEqual(out, expected) { t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out) } } func TestAgReqOverwrite(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} tplFlds := []*config.FCTemplate{ {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile(":", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("OverwrittenAccount", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("WithComposed", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if rcv, err := agReq.CGRReply.FieldAsInterface([]string{utils.AccountField}); err != nil { t.Error(err) } else if sls, canCast := rcv.([]*utils.DataNode); !canCast { t.Errorf("Cannot cast to &utils.NMSlice %+v", rcv) } else if len(sls) != 1 { t.Errorf("expecting: %+v, \n received: %+v ", 1, len(sls)) } else if (sls)[0].Value.Data != "OverwrittenAccountWithComposed" { t.Errorf("expecting: %+v, \n received: %+v ", "OverwrittenAccountWithComposed", (sls)[0].Value.Data) } } func TestAgReqGroupType(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} tplFlds := []*config.FCTemplate{ {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaGroup, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaGroup, Value: config.NewRSRParsersMustCompile("test", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if rcv, err := agReq.CGRReply.FieldAsInterface([]string{utils.AccountField}); err != nil { t.Error(err) } else if sls, canCast := rcv.([]*utils.DataNode); !canCast { t.Errorf("Cannot cast to &utils.NMSlice %+v", rcv) } else if len(sls) != 2 { t.Errorf("expecting: %+v, \n received: %+v ", 1, len(sls)) } else if (sls)[0].Value.Data != "cgrates.org" { t.Errorf("expecting: %+v, \n received: %+v ", "cgrates.org", (sls)[0].Value.Data) } else if (sls)[1].Value.Data != "test" { t.Errorf("expecting: %+v, \n received: %+v ", "test", (sls)[1].Value.Data) } } func TestAgReqSetFieldsInTmp(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaTmp + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaTmp + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.tmp, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.tmp) } } func TestAgReqSetFieldsIp2Hex(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: "IP", PathSlice: []string{"IP"}}, utils.NewLeafNode("62.87.114.244")) tplFlds := []*config.FCTemplate{ {Tag: "IP", Path: utils.MetaTmp + utils.NestingSep + "IP", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.IP{*ip2hex}", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{"IP"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "0x3e5772f4"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.tmp, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.tmp) } } func TestAgReqSetFieldsString2Hex(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: "CustomField", PathSlice: []string{"CustomField"}}, utils.NewLeafNode(string([]byte{0x94, 0x71, 0x02, 0x31, 0x01, 0x59}))) tplFlds := []*config.FCTemplate{ {Tag: "CustomField", Path: utils.MetaTmp + utils.NestingSep + "CustomField", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.CustomField{*string2hex}", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{"CustomField"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "0x947102310159"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.tmp, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.tmp) } } func TestAgReqSetFieldsWithRemove(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.CGRID, PathSlice: []string{utils.CGRID}}, utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String())) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Usage, PathSlice: []string{utils.Usage}}, utils.NewLeafNode(3*time.Minute)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ utils.CapAttributes: {Type: utils.NMMapType, Map: map[string]*utils.DataNode{ "PaypalAccount": utils.NewLeafNode("cgrates@paypal.com"), }}, utils.CapMaxUsage: utils.NewLeafNode(120 * time.Second), utils.Error: utils.NewLeafNode(""), }} tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaRep + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaRep + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Destination", Path: utils.MetaRep + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, {Tag: "RequestedUsageVoice", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*voice"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_seconds}", utils.InfieldSep)}, {Tag: "RequestedUsageData", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*data"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_nanoseconds}", utils.InfieldSep)}, {Tag: "RequestedUsageSMS", Path: utils.MetaRep + utils.NestingSep + "RequestedUsage", Type: utils.MetaVariable, Filters: []string{"*string:~*cgreq.ToR:*sms"}, Value: config.NewRSRParsersMustCompile( "~*cgreq.Usage{*duration_nanoseconds}", utils.InfieldSep)}, {Tag: "AttrPaypalAccount", Path: utils.MetaRep + utils.NestingSep + "PaypalAccount", Type: utils.MetaVariable, Filters: []string{"*empty:~*cgrep.Error:"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.Attributes.PaypalAccount", utils.InfieldSep)}, {Tag: "MaxUsage", Path: utils.MetaRep + utils.NestingSep + "MaxUsage", Type: utils.MetaVariable, Filters: []string{"*empty:~*cgrep.Error:"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.MaxUsage{*duration_seconds}", utils.InfieldSep)}, {Tag: "Error", Path: utils.MetaRep + utils.NestingSep + "Error", Type: utils.MetaVariable, Filters: []string{"*rsr:~*cgrep.Error:!^$"}, Value: config.NewRSRParsersMustCompile( "~*cgrep.Error", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := utils.NewOrderedNavigableMap() eMp.SetAsSlice(&utils.FullPath{Path: utils.Tenant, PathSlice: []string{utils.Tenant}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.SetAsSlice(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.SetAsSlice(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "RequestedUsage", PathSlice: []string{"RequestedUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "180"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "PaypalAccount", PathSlice: []string{"PaypalAccount"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates@paypal.com"}}}) eMp.SetAsSlice(&utils.FullPath{Path: "MaxUsage", PathSlice: []string{"MaxUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "120"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.Reply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.Reply) } tplFldsRemove := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaRep + utils.NestingSep + utils.Tenant, Type: utils.MetaRemove}, {Tag: "Account", Path: utils.MetaRep + utils.NestingSep + utils.AccountField, Type: utils.MetaRemove}, } for _, v := range tplFldsRemove { v.ComputePath() } eMpRemove := utils.NewOrderedNavigableMap() eMpRemove.SetAsSlice(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) eMpRemove.SetAsSlice(&utils.FullPath{Path: "RequestedUsage", PathSlice: []string{"RequestedUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "180"}}}) eMpRemove.SetAsSlice(&utils.FullPath{Path: "PaypalAccount", PathSlice: []string{"PaypalAccount"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates@paypal.com"}}}) eMpRemove.SetAsSlice(&utils.FullPath{Path: "MaxUsage", PathSlice: []string{"MaxUsage"}}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "120"}}}) if err := agReq.SetFields(tplFldsRemove); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.Reply, eMpRemove) { // when compare ignore orders t.Errorf("expecting: %+v,\n received: %+v", eMpRemove, agReq.Reply) } tplFldsRemove = []*config.FCTemplate{ {Path: utils.MetaRep, Type: utils.MetaRemoveAll}, } tplFldsRemove[0].ComputePath() eMpRemove = utils.NewOrderedNavigableMap() if err := agReq.SetFields(tplFldsRemove); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.Reply.GetOrder(), eMpRemove.GetOrder()) { t.Errorf("expecting: %+v,\n received: %+v", eMpRemove, agReq.Reply) } } func TestAgReqSetFieldsInCache(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaUCH + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaUCH + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if val, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.Tenant}); err != nil { t.Error(err) } else if val != "cgrates.org" { t.Errorf("expecting: %+v, \n received: %+v ", "cgrates.org", utils.ToJSON(val)) } if val, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.AccountField}); err != nil { t.Error(err) } else if val != "1001" { t.Errorf("expecting: %+v, \n received: %+v ", "1001", utils.ToJSON(val)) } if _, err := agReq.FieldAsInterface([]string{utils.MetaUCH, "Unexist"}); err == nil || err != utils.ErrNotFound { t.Error(err) } } func TestAgReqSetFieldsInCacheWithTimeOut(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) cfg.CacheCfg().Partitions[utils.CacheUCH].TTL = 5 * time.Millisecond engine.Cache = engine.NewCacheS(cfg, dm, nil) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaUCH + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaUCH + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if val, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.Tenant}); err != nil { t.Error(err) } else if val != "cgrates.org" { t.Errorf("expecting: %+v, \n received: %+v ", "cgrates.org", utils.ToJSON(val)) } if val, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.AccountField}); err != nil { t.Error(err) } else if val != "1001" { t.Errorf("expecting: %+v, \n received: %+v ", "1001", utils.ToJSON(val)) } if _, err := agReq.FieldAsInterface([]string{utils.MetaUCH, "Unexist"}); err == nil || err != utils.ErrNotFound { t.Error(err) } // give enough time to Cache to remove ttl the *uch time.Sleep(10 * time.Millisecond) if _, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.Tenant}); err != utils.ErrNotFound { t.Errorf("agReq.FieldAsInterface([]string{%q,%q}):got err=%v, want %v", utils.MetaUCH, utils.Tenant, err, utils.ErrNotFound) // Check item expiry time just in case. var expiryTime time.Time if err := engine.Cache.V1GetItemExpiryTime(context.Background(), &utils.ArgsGetCacheItemWithAPIOpts{ ArgsGetCacheItem: utils.ArgsGetCacheItem{ CacheID: utils.MetaUCH, ItemID: utils.Tenant, }, }, &expiryTime); err != nil { t.Logf("V1GetItemExpiryTime(%q,%q): got unexpected err=%v, item probably expired in the meantime", utils.MetaUCH, utils.Tenant, err) } t.Logf("item supposed to expire at %v, current time: %v", expiryTime, time.Now()) } if _, err := agReq.FieldAsInterface([]string{utils.MetaUCH, utils.AccountField}); err != utils.ErrNotFound { t.Errorf("agReq.FieldAsInterface([]string{%q,%q}):got err=%v, want %v", utils.MetaUCH, utils.AccountField, err, utils.ErrNotFound) // Check item expiry time just in case. var expiryTime time.Time if err := engine.Cache.V1GetItemExpiryTime(context.Background(), &utils.ArgsGetCacheItemWithAPIOpts{ ArgsGetCacheItem: utils.ArgsGetCacheItem{ CacheID: utils.MetaUCH, ItemID: utils.AccountField, }, }, &expiryTime); err != nil { t.Logf("V1GetItemExpiryTime(%q,%q): got unexpected err=%v, item probably expired in the meantime", utils.MetaUCH, utils.Tenant, err) } t.Logf("item supposed to expire at %v, current time: %v", expiryTime, time.Now()) } } func TestAgReqFiltersInsideField(t *testing.T) { //simulate the diameter request m := diam.NewRequest(diam.CreditControl, 4, nil) m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8")) m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("192.168.1.1")) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4)) m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(3)) m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(2)) m.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA")) m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org")) m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("voice@DiamItCCRInit")) m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 4, 15, 12, 20, 0, time.UTC))) m.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("1006")), // Subscription-Id-Data }}) m.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0)) m.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(0))}}) m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(250))}}) m.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ AVP: []*diam.AVP{ diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information AVP: []*diam.AVP{ diam.NewAVP(831, avp.Mbit, 10415, datatype.UTF8String("1006")), // Calling-Party-Address diam.NewAVP(832, avp.Mbit, 10415, datatype.UTF8String("1002")), // Called-Party-Address diam.NewAVP(20327, avp.Mbit, 2011, datatype.UTF8String("1002")), // Real-Called-Number diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(0)), // Charge-Flow-Type diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-Vlr-Number diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-CellID-Or-SAI diam.NewAVP(20313, avp.Mbit, 2011, datatype.OctetString("")), // Bearer-Capability diam.NewAVP(20321, avp.Mbit, 2011, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8")), // Call-Reference-Number diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String("")), // MSC-Address diam.NewAVP(20324, avp.Mbit, 2011, datatype.Unsigned32(0)), // Time-Zone diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("")), // Called-Party-NP diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String("")), // SSP-Time }, }), }}) //create diameterDataProvider cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) //pass the data provider to agent request agReq := NewAgentRequest(newDADataProvider(nil, m), nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "Usage", Path: utils.MetaCgreq + utils.NestingSep + utils.Usage, Type: utils.MetaCCUsage, Value: config.NewRSRParsersMustCompile("~*req.CC-Request-Number;~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/;5m", utils.InfieldSep)}, {Tag: "AnswerTime", Path: utils.MetaCgreq + utils.NestingSep + utils.AnswerTime, Type: utils.MetaDifference, Filters: []string{"*gt:~*cgreq.Usage:0s"}, // populate answer time if usage is greater than zero Value: config.NewRSRParsersMustCompile("~*req.Event-Timestamp;~*cgreq.Usage", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if val, err := agReq.FieldAsInterface([]string{utils.MetaCgreq, utils.AnswerTime}); err != nil { t.Error(err) } else if !val.(time.Time).Equal(time.Date(2018, 10, 4, 15, 3, 10, 0, time.UTC)) { t.Errorf("expecting: %+v, \n received: %+v ", time.Date(2018, 10, 4, 15, 3, 10, 0, time.UTC), val) } } func TestAgReqDynamicPath(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRRequest.Set(&utils.FullPath{Path: "Routes.CGR_ROUTE1", PathSlice: []string{"Routes", "CGR_ROUTE1"}}, utils.NewLeafNode(1001)) agReq.CGRRequest.Set(&utils.FullPath{Path: "Routes.CGR_ROUTE2", PathSlice: []string{"Routes", "CGR_ROUTE2"}}, utils.NewLeafNode(1002)) agReq.CGRRequest.Set(&utils.FullPath{Path: "BestRoute", PathSlice: []string{"BestRoute"}}, utils.NewLeafNode("ROUTE1")) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} val1, err := config.NewRSRParsersFromSlice([]string{"~*cgreq.Routes."}) if err != nil { t.Error(err) } tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Destination", Path: utils.MetaCgrep + utils.NestingSep + utils.Destination, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Destination", utils.InfieldSep)}, {Tag: "Usage", Path: utils.MetaCgrep + utils.NestingSep + utils.Usage, Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("30s", utils.InfieldSep)}, {Tag: "Route", Path: utils.MetaCgrep + utils.NestingSep + "Route", Type: utils.MetaVariable, Value: val1, }, {Tag: "Route2", Path: utils.MetaCgrep + utils.NestingSep + "Route2.", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Routes[CGR_ROUTE2]", utils.InfieldSep), }, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{utils.Destination}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) eMp.Set([]string{"Usage"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "30s"}}}) eMp.Set([]string{"Route"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{"Route2", "CGR_ROUTE1"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1002"}}}) if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eMp), utils.ToJSON(agReq.CGRReply)) } } func TestAgReqRoundingDecimals(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Cost, PathSlice: []string{utils.Cost}}, utils.NewLeafNode(12.12645)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} tplFlds := []*config.FCTemplate{ {Tag: "Cost", Path: utils.MetaCgrep + utils.NestingSep + utils.Cost, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("~*cgreq.Cost{*round:3}", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if rcv, err := agReq.CGRReply.FieldAsInterface([]string{utils.Cost}); err != nil { t.Error(err) } else if sls, canCast := rcv.([]*utils.DataNode); !canCast { t.Errorf("Cannot cast to &utils.NMSlice %+v", rcv) } else if len(sls) != 1 { t.Errorf("expecting: %+v, \n received: %+v ", 1, len(sls)) } else if (sls)[0].Value.Data != "12.126" { t.Errorf("expecting: %+v, \n received: %+v", "12.126", (sls)[0].Value.Data) } } /* $go test -bench=. -run=^$ -benchtime=10s -count=3 goos: linux goarch: amd64 pkg: github.com/cgrates/cgrates/agents BenchmarkAgReqSetField-16 990145 12012 ns/op BenchmarkAgReqSetField-16 1000000 12478 ns/op BenchmarkAgReqSetField-16 904732 13250 ns/op PASS ok github.com/cgrates/cgrates/agents 36.788s */ func BenchmarkAgReqSetField(b *testing.B) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { b.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) tplFlds := []*config.FCTemplate{ {Tag: "Tenant", Path: utils.MetaCgrep + utils.NestingSep + utils.Tenant, Type: utils.MetaComposed, Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep)}, {Tag: "Account", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField + "[0].ID", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cgreq.Account", utils.InfieldSep)}, {Tag: "Account2", Path: utils.MetaCgrep + utils.NestingSep + utils.AccountField + "[1].ID", Type: utils.MetaConstant, Value: config.NewRSRParsersMustCompile("1003", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } eMp := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} eMp.Set([]string{utils.Tenant}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "cgrates.org"}}}) eMp.Set([]string{utils.AccountField, "0", "ID"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1001"}}}) eMp.Set([]string{utils.AccountField, "1", "ID"}, []*utils.DataNode{ {Type: utils.NMDataType, Value: &utils.DataLeaf{Data: "1003"}}}) b.ResetTimer() for i := 0; i < b.N; i++ { agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set(&utils.FullPath{Path: utils.ToR, PathSlice: []string{utils.ToR}}, utils.NewLeafNode(utils.MetaVoice)) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AccountField, PathSlice: []string{utils.AccountField}}, utils.NewLeafNode("1001")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.Destination, PathSlice: []string{utils.Destination}}, utils.NewLeafNode("1002")) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.AnswerTime, PathSlice: []string{utils.AnswerTime}}, utils.NewLeafNode( time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC))) agReq.CGRRequest.Set(&utils.FullPath{Path: utils.RequestType, PathSlice: []string{utils.RequestType}}, utils.NewLeafNode(utils.MetaPrepaid)) agReq.CGRReply = &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{}} if err := agReq.SetFields(tplFlds); err != nil { b.Error(err) } else if !reflect.DeepEqual(agReq.CGRReply, eMp) { b.Errorf("expecting: %+v,\n received: %+v", eMp, agReq.CGRReply) } } } func TestAgReqNeedsMaxUsage(t *testing.T) { if needsMaxUsage(nil) { t.Error("Expected empty flag to not need maxUsage") } if needsMaxUsage(utils.FlagParams{}) { t.Error("Expected empty flag to not need maxUsage") } if needsMaxUsage(utils.FlagParams{utils.MetaIDs: {"ID1", "ID2"}}) { t.Error("Expected flag to not need maxUsage") } if !needsMaxUsage(utils.FlagParams{utils.MetaIDs: {"ID1", "ID2"}, utils.MetaInitiate: {}}) { t.Error("Expected flag to need maxUsage") } } func TestAgReqSetFieldsFromCfg(t *testing.T) { cfg := config.NewDefaultCGRConfig() data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items) if err != nil { t.Error(err) } dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, dm) agReq := NewAgentRequest(nil, nil, nil, nil, nil, nil, "cgrates.org", "", filterS, nil) tplFlds := []*config.FCTemplate{ {Tag: "CfgField", Path: utils.MetaCgreq + utils.NestingSep + "NodeID", Type: utils.MetaVariable, Value: config.NewRSRParsersMustCompile("~*cfg.general.node_id", utils.InfieldSep)}, } for _, v := range tplFlds { v.ComputePath() } if err := agReq.SetFields(tplFlds); err != nil { t.Error(err) } if val, err := agReq.FieldAsInterface([]string{utils.MetaCgreq, "NodeID"}); err != nil { t.Error(err) } else if val != config.CgrConfig().GeneralCfg().NodeID { t.Errorf("expecting: %+v, \n received: %+v ", config.CgrConfig().GeneralCfg().NodeID, utils.ToJSON(val)) } } func TestAgReqFieldsAsInterface(t *testing.T) { fldPath := []string{utils.MetaOpts, utils.AccountField} ar := &AgentRequest{ Request: nil, Vars: &utils.DataNode{}, CGRRequest: &utils.OrderedNavigableMap{}, diamreq: nil, tmp: &utils.DataNode{}, Opts: utils.MapStorage{ utils.AccountField: "Field1", }, } rcv, err := ar.FieldAsInterface(fldPath) rcvExpect := ar.Opts[utils.AccountField] if err != nil { t.Error(err) } else if rcv != rcvExpect { t.Errorf("Expected %v but received %v", rcvExpect, rcv) } //default case fldPath = []string{utils.MetaNone} _, err = ar.FieldAsInterface(fldPath) errExpect := "unsupported field prefix: <*none>" if err == nil || err.Error() != errExpect { t.Errorf("Expected %v but received %v", errExpect, err) } } func TestAgReqParseFieldDateTimeDaily(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*daily", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{ Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*daily", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*daily", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Day(), expected.Day()) { t.Errorf("Expected %v but received %v", finRes.Day(), expected.Day()) } } func TestAgReqParseFieldDateTimeTimeZone(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*daily", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*daily", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*daily", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Day(), expected.Day()) { t.Errorf("Expected %v but received %v", finRes.Day(), expected.Day()) } } func TestAgReqParseFieldDateTimeMonthly(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*monthly", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*monthly", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*monthly", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Month(), expected.Month()) { t.Errorf("Expected %v but received %v", finRes.Month(), expected.Month()) } } func TestAgReqParseFieldDateTimeMonthlyEstimated(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*monthly_estimated", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*monthly_estimated", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*monthly_estimated", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Month(), expected.Month()) { t.Errorf("Expected %v but received %v", finRes.Month(), expected.Month()) } } func TestAgReqParseFieldDateTimeYearly(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*yearly", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*yearly", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*yearly", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Year(), expected.Year()) { t.Errorf("Expected %v but received %v", finRes.Year(), expected.Year()) } } func TestAgReqParseFieldDateTimeMetaUnlimited(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile(utils.MetaUnlimited, utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile(utils.MetaUnlimited, utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout(utils.MetaUnlimited, utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Day(), expected.Day()) { t.Errorf("Expected %v but received %v", finRes.Day(), expected.Day()) } } func TestAgReqParseFieldDateTimeEmpty(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Day(), expected.Day()) { t.Errorf("Expected %v but received %v", finRes.Day(), expected.Day()) } } func TestAgReqParseFieldDateTimeMonthEnd(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*month_endTest", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*month_endTest", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "Local", } result, err := AgentReq.ParseField(fctTemp) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } expected, err := utils.ParseTimeDetectLayout("*month_endTest", utils.FirstNonEmpty(fctTemp.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone)) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } strRes := fmt.Sprintf("%v", result) finRes, err := time.Parse("“Mon Jan _2 15:04:05 2006”", strRes) if err != nil { t.Errorf("Expected %v but received %v", nil, err) } if !reflect.DeepEqual(finRes.Day(), expected.Day()) { t.Errorf("Expected %v but received %v", finRes.Day(), expected.Day()) } } func TestAgReqParseFieldDateTimeError(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("*month_endTest", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: config.NewRSRParsersMustCompile("*month_endTest", utils.InfieldSep), Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "/", } _, err := AgentReq.ParseField(fctTemp) expected := "time: invalid location name" if err == nil || err.Error() != expected { t.Errorf("Expected <%+v> but received <%+v>", expected, err) } } func TestAgReqParseFieldDateTimeError2(t *testing.T) { prsr, err := config.NewRSRParsersFromSlice([]string{"2.", "~*req.CGRID<~*opts.Converter>"}) if err != nil { t.Fatal(err) } AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, prsr, "", "", nil, nil) fctTemp := &config.FCTemplate{Type: utils.MetaDateTime, Value: prsr, Layout: "“Mon Jan _2 15:04:05 2006”", Timezone: "/", } _, err = AgentReq.ParseField(fctTemp) expected := utils.ErrNotFound if err == nil || err != expected { t.Errorf("Expected <%+v> but received <%+v>", expected, err) } } func TestAgReqRemoveAll(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, nil, tntTpl, "", "", nil, nil) testCases := []struct { prefix string isError bool }{ {prefix: utils.MetaVars, isError: false}, {prefix: utils.MetaCgreq, isError: false}, {prefix: utils.MetaCgrep, isError: false}, {prefix: utils.MetaRep, isError: false}, {prefix: utils.MetaDiamreq, isError: false}, {prefix: utils.MetaTmp, isError: false}, {prefix: utils.MetaUCH, isError: false}, {prefix: utils.MetaOpts, isError: false}, {prefix: "unsupported_prefix", isError: true}, } for _, testCase := range testCases { err := AgentReq.RemoveAll(testCase.prefix) if testCase.isError && err == nil { t.Fatalf("expected an error for prefix: <%s>, but got no error", testCase.prefix) } if !testCase.isError && err != nil { t.Fatalf("expected no error for prefix: <%s>, but got error: %v", testCase.prefix, err) } } } func TestAgReqRemove(t *testing.T) { tntTpl := config.NewRSRParsersMustCompile("", utils.InfieldSep) AgentReq := NewAgentRequest(utils.MapStorage{}, nil, nil, nil, utils.MapStorage{utils.AccountField: "Field1"}, tntTpl, "", "", nil, nil) testCases := []struct { fullPath *utils.FullPath isError bool }{ {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaVars}, Path: utils.MetaVars + utils.NestingSep + utils.AccountField}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaCgreq}, Path: utils.MetaCgreq + utils.NestingSep + utils.Usage}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaCgrep}}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaRep}, Path: utils.MetaRep + utils.NestingSep + "MaxUsage"}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaDiamreq}, Path: utils.MetaDiamreq + utils.NestingSep + "Destination-Host"}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaRadDAReq}, Path: utils.MetaRadDAReq + utils.NestingSep + "User-Name"}, isError: false}, {fullPath: &utils.FullPath{PathSlice: []string{"unsupported_prefix"}}, isError: true}, } for _, testCase := range testCases { err := AgentReq.Remove(testCase.fullPath) if testCase.isError && err == nil { t.Fatalf("expected an error for fullPath: <%v>, but got no error", testCase.fullPath) } if !testCase.isError && err != nil { t.Fatalf("expected no error for fullPath: <%v>, but got error: %v", testCase.fullPath, err) } } } // func TestAgentRequestAppend(t *testing.T) { // tntTpl := config.NewRSRParsersMustCompile("", utils.InfieldSep) // ar := NewAgentRequest(utils.MapStorage{}, &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{ // utils.MetaAppID: utils.NewLeafNode("appID")}}, nil, nil, utils.MapStorage{utils.AccountField: "Field1"}, tntTpl, "", "", nil, nil) // testCases := []struct { // fullPath *utils.FullPath // val *utils.DataLeaf // isError bool // }{ // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaVars}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaCgreq}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaCgrep}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaRep}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaDiamreq}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaTmp}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaOpts}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{utils.MetaUCH}}, val: &utils.DataLeaf{Data: "test"}, isError: false}, // {fullPath: &utils.FullPath{PathSlice: []string{"unsupported_prefix"}}, val: &utils.DataLeaf{Data: "test"}, isError: true}, // } // for _, testCase := range testCases { // err := ar.Append(testCase.fullPath, testCase.val) // if testCase.isError && err == nil { // t.Fatalf("expected an error for fullPath: <%v>, but got no error", testCase.fullPath) // } // if !testCase.isError && err != nil { // t.Fatalf("expected no error for fullPath: <%v>, but got error: %v", testCase.fullPath, err) // } // } // } func TestAgReqString(t *testing.T) { sampleRequest := &AgentRequest{ Request: nil, Vars: nil, CGRRequest: nil, CGRReply: nil, Reply: nil, Tenant: "cgrates.org", Timezone: "UTC", filterS: nil, diamreq: nil, tmp: nil, Opts: utils.MapStorage{}, ExtraDP: map[string]utils.DataProvider{}, } output := sampleRequest.String() expected := utils.ToIJSON(sampleRequest) if diff := cmp.Diff(expected, output); diff != "" { t.Errorf("String() returned unexpected value: diff (-expected +got):\n%s", diff) } } func TestCacheRadiusPacket(t *testing.T) { testPacket := &radigo.Packet{} testAddress := "test.address" testCfg := &config.RadiusAgentCfg{ ClientDaAddresses: map[string]config.DAClientOpts{ "allowed.address": {}, }, } t.Run("Success", func(t *testing.T) { err := cacheRadiusPacket(testPacket, testAddress, testCfg, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } }) t.Run("Address does not match client", func(t *testing.T) { err := cacheRadiusPacket(testPacket, "not.allowed", testCfg, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } }) } func TestGigawordsCalculateTotalOctets(t *testing.T) { // Renamed for clarity var gigawordMultiplier int64 = 4294967296 configTemplate := ` { "diameter_agent": { "request_processors": [ { "id": "test_proc", "filters": [], "flags": [], "request_fields": [ %s ] } ] } }` inputFieldConfig := `{ "tag": "TotalUsageInput", "path": "*cgreq.TotalUsageInput", "type": "*sum", "value": "~*req.Acct-Input-Gigawords{*gigawords};~*req.Acct-Input-Octets" }` outputFieldConfig := `{ "tag": "TotalUsageOutput", "path": "*cgreq.TotalUsageOutput", "type": "*sum", "value": "~*req.Acct-Output-Gigawords{*gigawords};~*req.Acct-Output-Octets" }` testCases := []struct { name string fieldConfig string inputDP utils.MapStorage expectedValue int64 expectErr bool err error }{ { name: "Input: Zero GW, Zero Octets", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": 0, "Acct-Input-Octets": 0, }, expectedValue: 0, }, { name: "Input: Zero GW, Some Octets", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": 0, "Acct-Input-Octets": 12345, }, expectedValue: 12345, }, { name: "Input: Some GW (2), Zero Octets", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": 2, "Acct-Input-Octets": 0, }, expectedValue: 2 * gigawordMultiplier, }, { name: "Input: Some GW (3), Some Octets (1000)", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": 3, "Acct-Input-Octets": 1000, }, expectedValue: (3 * gigawordMultiplier) + 1000, }, { name: "Input: Missing GW, Some Octets", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Octets": 50000, }, expectedValue: 0, expectErr: true, err: utils.ErrNotFound, }, { name: "Input: Some GW, Missing Octets", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": 1, }, expectErr: true, err: utils.ErrNotFound, }, { name: "Input: Both GW and Octets Missing", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{}, expectedValue: 0, expectErr: true, err: utils.ErrNotFound, }, { name: "Input: GW as String '2', Octets as String '333'", fieldConfig: inputFieldConfig, inputDP: utils.MapStorage{ "Acct-Input-Gigawords": "2", "Acct-Input-Octets": "333", }, expectedValue: (2 * gigawordMultiplier) + 333, }, { name: "Output: Zero GW, Zero Octets", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Gigawords": 0, "Acct-Output-Octets": 0, }, expectedValue: 0, }, { name: "Output: Zero GW, Some Octets", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Gigawords": 0, "Acct-Output-Octets": 98765, }, expectedValue: 98765, }, { name: "Output: Some GW (1), Zero Octets", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Gigawords": 1, "Acct-Output-Octets": 0, }, expectedValue: 1 * gigawordMultiplier, }, { name: "Output: Some GW (4), Some Octets (20000)", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Gigawords": 4, "Acct-Output-Octets": 20000, }, expectedValue: (4 * gigawordMultiplier) + 20000, }, { name: "Output: Missing GW, Some Octets", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Octets": 777, }, expectedValue: 0, expectErr: true, err: utils.ErrNotFound, }, { name: "Output: Some GW, Missing Octets", fieldConfig: outputFieldConfig, inputDP: utils.MapStorage{ "Acct-Output-Gigawords": 2, }, expectErr: true, err: utils.ErrNotFound, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { fullConf := fmt.Sprintf(configTemplate, tc.fieldConfig) cgrconf, err := config.NewCGRConfigFromJSONStringWithDefaults(fullConf) if err != nil { t.Fatalf("Config parsing failed: %v", err) } agReq := NewAgentRequest(tc.inputDP, nil, nil, nil, nil, nil, "cgrates.org", "", nil, nil) fieldDef := cgrconf.DiameterAgentCfg().RequestProcessors[0].RequestFields[0] out, err := agReq.ParseField(fieldDef) if tc.expectErr { if err == nil || err.Error() != tc.err.Error() { t.Fatalf("Expected error <%v>, but got <%v>", tc.err, err) } return } if err != nil { t.Fatalf("ParseField failed unexpectedly: %v", err) } resultInt64, ok := out.(int64) if !ok { t.Fatal("ParseField result type is not int64") } else { if resultInt64 != tc.expectedValue { t.Errorf("Expected result %d, but got %d", tc.expectedValue, resultInt64) } } }) } }