diff --git a/agents/diamagent.go b/agents/diamagent.go index 3dadc2538..9418b51a7 100644 --- a/agents/diamagent.go +++ b/agents/diamagent.go @@ -297,6 +297,7 @@ func (da *DiameterAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), ) rply := new(sessions.V1AuthorizeReply) err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1AuthorizeEvent, @@ -368,7 +369,9 @@ func (da *DiameterAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersIgnoreErrors), reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, - reqProcessor.Flags.HasKey(utils.MetaFD)) + reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), + ) rply := new(sessions.V1ProcessMessageReply) err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1ProcessMessage, msgArgs, rply) diff --git a/agents/dnsagent.go b/agents/dnsagent.go index 8d99f0f7a..65f10fc0a 100644 --- a/agents/dnsagent.go +++ b/agents/dnsagent.go @@ -218,6 +218,7 @@ func (da *DNSAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), ) rply := new(sessions.V1AuthorizeReply) err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil, @@ -293,7 +294,9 @@ func (da *DNSAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersIgnoreErrors), reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, - reqProcessor.Flags.HasKey(utils.MetaFD)) + reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), + ) rply := new(sessions.V1ProcessMessageReply) // need it so rpcclient can clone err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil, utils.SessionSv1ProcessMessage, diff --git a/agents/httpagent.go b/agents/httpagent.go index 690a42374..cdeaee052 100644 --- a/agents/httpagent.go +++ b/agents/httpagent.go @@ -153,6 +153,7 @@ func (ha *HTTPAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), ) rply := new(sessions.V1AuthorizeReply) err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1AuthorizeEvent, @@ -224,7 +225,9 @@ func (ha *HTTPAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersIgnoreErrors), reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, - reqProcessor.Flags.HasKey(utils.MetaFD)) + reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), + ) rply := new(sessions.V1ProcessMessageReply) err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1ProcessMessage, evArgs, rply) diff --git a/agents/kamevent_test.go b/agents/kamevent_test.go index 97c548ac1..7e1d7a217 100644 --- a/agents/kamevent_test.go +++ b/agents/kamevent_test.go @@ -191,6 +191,56 @@ func TestKamEvV1AuthorizeArgs(t *testing.T) { } } +func TestKamEvV1AuthorizeArgs2(t *testing.T) { + timezone := config.CgrConfig().GeneralCfg().DefaultTimezone + kamEv := KamEvent{"event": "CGR_CALL_END", + "callid": "46c01a5c249b469e76333fc6bfa87f6a@0:0:0:0:0:0:0:0", + "from_tag": "bf71ad59", "to_tag": "7351fecf", + "cgr_reqtype": utils.META_POSTPAID, "cgr_account": "1001", + "cgr_destination": "1002", "cgr_answertime": "1419839310", + "cgr_duration": "3", "cgr_pdd": "4", + utils.CGR_SUPPLIER: "supplier2", + utils.CGR_DISCONNECT_CAUSE: "200", + utils.CGRFlags: "*accounts,*suppliers,*suppliers_maxcost:100,*suppliers_ignore_errors"} + sTime, err := utils.ParseTimeDetectLayout(kamEv[utils.AnswerTime], timezone) + if err != nil { + return + } + expected := &sessions.V1AuthorizeArgs{ + GetMaxUsage: true, + CGREvent: &utils.CGREvent{ + Tenant: utils.FirstNonEmpty(kamEv[utils.Tenant], + config.CgrConfig().GeneralCfg().DefaultTenant), + ID: utils.UUIDSha1Prefix(), + Time: &sTime, + Event: kamEv.AsMapStringInterface(), + }, + GetSuppliers: true, + SuppliersIgnoreErrors: true, + SuppliersMaxCost: "100", + } + rcv := kamEv.V1AuthorizeArgs() + if !reflect.DeepEqual(expected.CGREvent.Tenant, rcv.CGREvent.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", expected.CGREvent.Tenant, rcv.CGREvent.Tenant) + } else if !reflect.DeepEqual(expected.CGREvent.Time, rcv.CGREvent.Time) { + t.Errorf("Expecting: %+v, received: %+v", expected.CGREvent.Time, rcv.CGREvent.Time) + } else if !reflect.DeepEqual(expected.CGREvent.Event, rcv.CGREvent.Event) { + t.Errorf("Expecting: %+v, received: %+v", expected.CGREvent.Event, rcv.CGREvent.Event) + } else if !reflect.DeepEqual(expected.CGREvent.Event, rcv.CGREvent.Event) { + t.Errorf("Expecting: %+v, received: %+v", expected.CGREvent.Event, rcv.CGREvent.Event) + } else if !reflect.DeepEqual(expected.GetMaxUsage, rcv.GetMaxUsage) { + t.Errorf("Expecting: %+v, received: %+v", expected.GetMaxUsage, rcv.GetMaxUsage) + } else if !reflect.DeepEqual(expected.GetSuppliers, rcv.GetSuppliers) { + t.Errorf("Expecting: %+v, received: %+v", expected.GetSuppliers, rcv.GetSuppliers) + } else if !reflect.DeepEqual(expected.GetAttributes, rcv.GetAttributes) { + t.Errorf("Expecting: %+v, received: %+v", expected.GetAttributes, rcv.GetAttributes) + } else if !reflect.DeepEqual(expected.SuppliersMaxCost, rcv.SuppliersMaxCost) { + t.Errorf("Expecting: %+v, received: %+v", expected.SuppliersMaxCost, rcv.SuppliersMaxCost) + } else if !reflect.DeepEqual(expected.SuppliersIgnoreErrors, rcv.SuppliersIgnoreErrors) { + t.Errorf("Expecting: %+v, received: %+v", expected.SuppliersIgnoreErrors, rcv.SuppliersIgnoreErrors) + } +} + func TestKamEvAsKamAuthReply(t *testing.T) { timezone := config.CgrConfig().GeneralCfg().DefaultTimezone kamEv := KamEvent{"event": "CGR_CALL_END", diff --git a/agents/radagent.go b/agents/radagent.go index 2675aa25c..a9028fcdc 100644 --- a/agents/radagent.go +++ b/agents/radagent.go @@ -194,6 +194,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), ) rply := new(sessions.V1AuthorizeReply) err = ra.connMgr.Call(ra.cgrCfg.RadiusAgentCfg().SessionSConns, nil, utils.SessionSv1AuthorizeEvent, @@ -265,7 +266,9 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RequestProcessor, reqProcessor.Flags.HasKey(utils.MetaSuppliersIgnoreErrors), reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, - reqProcessor.Flags.HasKey(utils.MetaFD)) + reqProcessor.Flags.HasKey(utils.MetaFD), + reqProcessor.Flags.ParamValue(utils.MetaSuppliersMaxCost), + ) rply := new(sessions.V1ProcessMessageReply) err = ra.connMgr.Call(ra.cgrCfg.RadiusAgentCfg().SessionSConns, nil, utils.SessionSv1ProcessMessage, evArgs, rply) if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) { diff --git a/ers/ers.go b/ers/ers.go index 2dafef6c1..710ccb636 100644 --- a/ers/ers.go +++ b/ers/ers.go @@ -198,6 +198,7 @@ func (erS *ERService) processEvent(cgrEv *utils.CGREvent, rdrCfg *config.EventRe rdrCfg.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, rdrCfg.Flags.HasKey(utils.MetaFD), + rdrCfg.Flags.ParamValue(utils.MetaSuppliersMaxCost), ) rply := new(sessions.V1AuthorizeReply) err = erS.connMgr.Call(erS.cfg.ERsCfg().SessionSConns, nil, utils.SessionSv1AuthorizeEvent, @@ -254,7 +255,8 @@ func (erS *ERService) processEvent(cgrEv *utils.CGREvent, rdrCfg *config.EventRe rdrCfg.Flags.HasKey(utils.MetaSuppliersIgnoreErrors), rdrCfg.Flags.HasKey(utils.MetaSuppliersEventCost), cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, - rdrCfg.Flags.HasKey(utils.MetaFD)) + rdrCfg.Flags.HasKey(utils.MetaFD), + rdrCfg.Flags.ParamValue(utils.MetaSuppliersMaxCost)) rply := new(sessions.V1ProcessMessageReply) // need it so rpcclient can clone err = erS.connMgr.Call(erS.cfg.ERsCfg().SessionSConns, nil, utils.SessionSv1ProcessMessage, evArgs, rply) diff --git a/general_tests/sessionsuppliers_it_test.go b/general_tests/sessionsuppliers_it_test.go new file mode 100644 index 000000000..6dd578184 --- /dev/null +++ b/general_tests/sessionsuppliers_it_test.go @@ -0,0 +1,528 @@ +// +build integration + +/* +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 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package general_tests + +import ( + "net/rpc" + "path" + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/sessions" + "github.com/cgrates/cgrates/utils" +) + +var ( + sesSupplierSCfgDir string + sesSupplierSCfgPath string + sesSupplierSCfg *config.CGRConfig + sesSupplierSRPC *rpc.Client + + sesSupplierSTests = []func(t *testing.T){ + testSesSupplierSItLoadConfig, + testSesSupplierSItResetDataDB, + testSesSupplierSItResetStorDb, + testSesSupplierSItStartEngine, + testSesSupplierSItRPCConn, + testSesSupplierSItLoadFromFolder, + + testSesSupplierSAuthorizeEvent, + testSesSupplierSProcessMessage, + testSesSupplierSProcessEvent, + + testSesSupplierSItStopCgrEngine, + } +) + +func TestSesSupplierSItSessions(t *testing.T) { + switch *dbType { + case utils.MetaInternal: + sesSupplierSCfgDir = "tutinternal" + case utils.MetaMySQL: + sesSupplierSCfgDir = "tutmysql" + case utils.MetaMongo: + sesSupplierSCfgDir = "tutmongo" + case utils.MetaPostgres: + t.SkipNow() + default: + t.Fatal("Unknown Database type") + } + for _, stest := range sesSupplierSTests { + t.Run(sesSupplierSCfgDir, stest) + } +} + +func testSesSupplierSItLoadConfig(t *testing.T) { + sesSupplierSCfgPath = path.Join(*dataDir, "conf", "samples", sesSupplierSCfgDir) + if sesSupplierSCfg, err = config.NewCGRConfigFromPath(sesSupplierSCfgPath); err != nil { + t.Error(err) + } +} + +func testSesSupplierSItResetDataDB(t *testing.T) { + if err := engine.InitDataDb(sesSupplierSCfg); err != nil { + t.Fatal(err) + } +} + +func testSesSupplierSItResetStorDb(t *testing.T) { + if err := engine.InitStorDb(sesSupplierSCfg); err != nil { + t.Fatal(err) + } +} + +func testSesSupplierSItStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(sesSupplierSCfgPath, *waitRater); err != nil { + t.Fatal(err) + } +} + +func testSesSupplierSItRPCConn(t *testing.T) { + var err error + sesSupplierSRPC, err = newRPCClient(sesSupplierSCfg.ListenCfg()) + if err != nil { + t.Fatal(err) + } +} + +func testSesSupplierSItLoadFromFolder(t *testing.T) { + var reply string + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testit")} + if err := sesSupplierSRPC.Call(utils.APIerSv1LoadTariffPlanFromFolder, attrs, &reply); err != nil { + t.Error(err) + } + time.Sleep(100 * time.Millisecond) +} + +func testSesSupplierSAuthorizeEvent(t *testing.T) { + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.Source: "testV4CDRsProcessCDR", + utils.OriginID: "testV4CDRsProcessCDR", + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.META_POSTPAID, + utils.Category: utils.CALL, + utils.Account: "1003", + utils.Subject: "1003", + utils.Destination: "1002", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.SetupTime: time.Date(2018, 8, 24, 16, 00, 00, 0, time.UTC), + utils.Usage: time.Minute, + }, + } + args := sessions.NewV1AuthorizeArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "") + + var rply sessions.V1AuthorizeReply + if err := sesSupplierSRPC.Call(utils.SessionSv1AuthorizeEvent, args, &rply); err != nil { + t.Fatal(err) + } + expected := sessions.V1AuthorizeReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 3, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, { + SupplierID: "supplier2", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 1.2, + "RatingPlanID": "RP_RETAIL1", + "Weight": 20., + }, + }, + }, + }, + } + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + args = sessions.NewV1AuthorizeArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "2") + + rply = sessions.V1AuthorizeReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + expected = sessions.V1AuthorizeReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 2, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, + }, + }, + } + + args = sessions.NewV1AuthorizeArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "1") + + rply = sessions.V1AuthorizeReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + args = sessions.NewV1AuthorizeArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, true, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "") + + rply = sessions.V1AuthorizeReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } +} + +func testSesSupplierSProcessMessage(t *testing.T) { + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.Source: "testV4CDRsProcessCDR", + utils.OriginID: "testV4CDRsProcessCDR", + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.META_POSTPAID, + utils.Category: utils.CALL, + utils.Account: "1003", + utils.Subject: "1003", + utils.Destination: "1002", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.SetupTime: time.Date(2018, 8, 24, 16, 00, 00, 0, time.UTC), + utils.Usage: time.Minute, + }, + } + args := sessions.NewV1ProcessMessageArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "") + + var rply sessions.V1ProcessMessageReply + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + expected := sessions.V1ProcessMessageReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 3, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, { + SupplierID: "supplier2", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 1.2, + "RatingPlanID": "RP_RETAIL1", + "Weight": 20., + }, + }, + }, + }, + } + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + args = sessions.NewV1ProcessMessageArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "2") + + rply = sessions.V1ProcessMessageReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + expected = sessions.V1ProcessMessageReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 2, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, + }, + }, + } + + args = sessions.NewV1ProcessMessageArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, false, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "1") + + rply = sessions.V1ProcessMessageReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + args = sessions.NewV1ProcessMessageArgs(false, []string{}, + false, []string{}, false, []string{}, false, false, + true, false, true, cgrEv, &utils.ArgDispatcher{}, utils.Paginator{}, false, "") + + rply = sessions.V1ProcessMessageReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessMessage, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } +} + +func testSesSupplierSProcessEvent(t *testing.T) { + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + utils.Source: "testV4CDRsProcessCDR", + utils.OriginID: "testV4CDRsProcessCDR", + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.META_POSTPAID, + utils.Category: utils.CALL, + utils.Account: "1003", + utils.Subject: "1003", + utils.Destination: "1002", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.SetupTime: time.Date(2018, 8, 24, 16, 00, 00, 0, time.UTC), + utils.Usage: time.Minute, + }, + } + args := sessions.V1ProcessEventArgs{ + Flags: []string{"*suppliers"}, + CGREvent: cgrEv, + Paginator: utils.Paginator{}, + } + + var rply sessions.V1ProcessEventReply + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessEvent, args, &rply); err != nil { + t.Fatal(err) + } + expected := sessions.V1ProcessEventReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 3, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, { + SupplierID: "supplier2", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 1.2, + "RatingPlanID": "RP_RETAIL1", + "Weight": 20., + }, + }, + }, + }, + } + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + args = sessions.V1ProcessEventArgs{ + Flags: []string{"*suppliers", "*suppliers_maxcost:2"}, + CGREvent: cgrEv, + Paginator: utils.Paginator{}, + } + + rply = sessions.V1ProcessEventReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessEvent, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + expected = sessions.V1ProcessEventReply{ + Suppliers: &engine.SortedSuppliers{ + ProfileID: "SPL_LEASTCOST_1", + Sorting: "*lc", + Count: 2, + SortedSuppliers: []*engine.SortedSupplier{ + { + SupplierID: "supplier3", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 15., + }, + }, { + SupplierID: "supplier1", + SupplierParameters: "", + SortingData: map[string]interface{}{ + "Cost": 0.0102, + "RatingPlanID": "RP_SPECIAL_1002", + "Weight": 10., + }, + }, + }, + }, + } + + args = sessions.V1ProcessEventArgs{ + Flags: []string{"*suppliers", "*suppliers_maxcost:1"}, + CGREvent: cgrEv, + Paginator: utils.Paginator{}, + } + rply = sessions.V1ProcessEventReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessEvent, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } + + args = sessions.V1ProcessEventArgs{ + Flags: []string{"*suppliers:*event_cost"}, + CGREvent: cgrEv, + Paginator: utils.Paginator{}, + } + + rply = sessions.V1ProcessEventReply{} + if err := sesSupplierSRPC.Call(utils.SessionSv1ProcessEvent, + args, &rply); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(rply, expected) { + t.Errorf("Expected: %s, received: %s", utils.ToJSON(expected), utils.ToJSON(rply)) + } +} + +func testSesSupplierSItStopCgrEngine(t *testing.T) { + if err := engine.KillEngine(100); err != nil { + t.Error(err) + } +} diff --git a/packages/debian/changelog b/packages/debian/changelog index 394175857..cfa83d3d7 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -9,6 +9,7 @@ cgrates (0.10.3~dev) UNRELEASED; urgency=medium * [SessionS] Added extra condition to determine if the increment is considered the roundIncrement * [SessionS] Cloned the charging interval added on EventCost merge * [FilterS] Optimized the automated index fields matching + * [AgentS] Added *routes_maxcost flag -- DanB Thu, 08 Oct 2020 16:23:58 +0300 diff --git a/sessions/sessions.go b/sessions/sessions.go index 44acf47cb..cab373f53 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -1703,7 +1703,7 @@ func NewV1AuthorizeArgs(attrs bool, attributeIDs []string, thrslds bool, thresholdIDs []string, statQueues bool, statIDs []string, res, maxUsage, suppls, supplsIgnoreErrs, supplsEventCost bool, cgrEv *utils.CGREvent, argDisp *utils.ArgDispatcher, - supplierPaginator utils.Paginator, forceDuration bool) (args *V1AuthorizeArgs) { + supplierPaginator utils.Paginator, forceDuration bool, supMaxCost string) (args *V1AuthorizeArgs) { args = &V1AuthorizeArgs{ GetAttributes: attrs, AuthorizeResources: res, @@ -1716,7 +1716,9 @@ func NewV1AuthorizeArgs(attrs bool, attributeIDs []string, ForceDuration: forceDuration, } if supplsEventCost { - args.SuppliersMaxCost = utils.MetaSuppliersEventCost + args.SuppliersMaxCost = utils.MetaEventCost + } else { + args.SuppliersMaxCost = supMaxCost } args.ArgDispatcher = argDisp args.Paginator = supplierPaginator @@ -1769,6 +1771,8 @@ func (args *V1AuthorizeArgs) ParseFlags(flags string) { args.SuppliersIgnoreErrors = true case subsystem == utils.MetaSuppliersEventCost: args.SuppliersMaxCost = utils.MetaEventCost + case strings.HasPrefix(subsystem, utils.MetaSuppliersMaxCost): + args.SuppliersMaxCost = strings.TrimPrefix(subsystem, utils.MetaSuppliersMaxCost+utils.InInFieldSep) case strings.HasPrefix(subsystem, utils.MetaAttributes): args.GetAttributes = true args.AttributeIDs = getFlagIDs(subsystem) @@ -2709,7 +2713,7 @@ func NewV1ProcessMessageArgs(attrs bool, attributeIDs []string, thds bool, thresholdIDs []string, stats bool, statIDs []string, resrc, acnts, suppls, supplsIgnoreErrs, supplsEventCost bool, cgrEv *utils.CGREvent, argDisp *utils.ArgDispatcher, - supplierPaginator utils.Paginator, forceDuration bool) (args *V1ProcessMessageArgs) { + supplierPaginator utils.Paginator, forceDuration bool, supMaxCost string) (args *V1ProcessMessageArgs) { args = &V1ProcessMessageArgs{ AllocateResources: resrc, Debit: acnts, @@ -2723,7 +2727,9 @@ func NewV1ProcessMessageArgs(attrs bool, attributeIDs []string, ForceDuration: forceDuration, } if supplsEventCost { - args.SuppliersMaxCost = utils.MetaSuppliersEventCost + args.SuppliersMaxCost = utils.MetaEventCost + } else { + args.SuppliersMaxCost = supMaxCost } args.Paginator = supplierPaginator if len(attributeIDs) != 0 { @@ -2774,6 +2780,8 @@ func (args *V1ProcessMessageArgs) ParseFlags(flags string) { args.SuppliersIgnoreErrors = true case subsystem == utils.MetaSuppliersEventCost: args.SuppliersMaxCost = utils.MetaEventCost + case strings.HasPrefix(subsystem, utils.MetaSuppliersMaxCost): + args.SuppliersMaxCost = strings.TrimPrefix(subsystem, utils.MetaSuppliersMaxCost+utils.InInFieldSep) case strings.Index(subsystem, utils.MetaAttributes) != -1: args.GetAttributes = true args.AttributeIDs = getFlagIDs(subsystem) @@ -3228,8 +3236,8 @@ func (sS *SessionS) BiRPCv1ProcessEvent(clnt rpcclient.ClientConnector, // get suppliers if required if argsFlagsWithParams.HasKey(utils.MetaSuppliers) { var ignoreErrors bool - var maxCost string // check in case we have options for suppliers + maxCost := argsFlagsWithParams.ParamValue(utils.MetaSuppliersMaxCost) if splOpts := argsFlagsWithParams.ParamsSlice(utils.MetaSuppliers); len(splOpts) != 0 { //check for subflags and convert them into utils.FlagsWithParams splsFlagsWithParams, err := utils.FlagsWithParamsFromSlice(splOpts) @@ -3240,7 +3248,7 @@ func (sS *SessionS) BiRPCv1ProcessEvent(clnt rpcclient.ClientConnector, ignoreErrors = true } if splsFlagsWithParams.HasKey(utils.MetaEventCost) { - maxCost = utils.MetaSuppliersEventCost + maxCost = utils.MetaEventCost } } splsReply, err := sS.getSuppliers(args.CGREvent.Clone(), args.ArgDispatcher, diff --git a/sessions/sessions_test.go b/sessions/sessions_test.go index b4243e4e7..ca3af4777 100644 --- a/sessions/sessions_test.go +++ b/sessions/sessions_test.go @@ -827,7 +827,7 @@ func TestSessionSNewV1AuthorizeArgs(t *testing.T) { GetAttributes: true, CGREvent: cgrEv, } - rply := NewV1AuthorizeArgs(true, nil, false, nil, false, nil, true, false, false, false, false, cgrEv, nil, utils.Paginator{}, false) + rply := NewV1AuthorizeArgs(true, nil, false, nil, false, nil, true, false, false, false, false, cgrEv, nil, utils.Paginator{}, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } @@ -839,11 +839,11 @@ func TestSessionSNewV1AuthorizeArgs(t *testing.T) { ProcessStats: true, GetSuppliers: false, SuppliersIgnoreErrors: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, CGREvent: cgrEv, ForceDuration: true, } - rply = NewV1AuthorizeArgs(true, nil, false, nil, true, nil, false, true, false, true, true, cgrEv, nil, utils.Paginator{}, true) + rply = NewV1AuthorizeArgs(true, nil, false, nil, true, nil, false, true, false, true, true, cgrEv, nil, utils.Paginator{}, true, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v,\n received: %+v", expected, rply) } @@ -859,14 +859,34 @@ func TestSessionSNewV1AuthorizeArgs(t *testing.T) { ProcessStats: true, GetSuppliers: false, SuppliersIgnoreErrors: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, CGREvent: cgrEv, AttributeIDs: []string{"ATTR1", "ATTR2"}, ThresholdIDs: []string{"ID1", "ID2"}, StatIDs: []string{"test3", "test4"}, } rply = NewV1AuthorizeArgs(true, attributeIDs, false, thresholdIDs, true, statIDs, - false, true, false, true, true, cgrEv, nil, utils.Paginator{}, false) + false, true, false, true, true, cgrEv, nil, utils.Paginator{}, false, "") + if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v,\n received: %+v", expected, rply) + } + + expected = &V1AuthorizeArgs{ + GetAttributes: true, + AuthorizeResources: false, + GetMaxUsage: true, + ProcessThresholds: false, + ProcessStats: true, + GetSuppliers: true, + SuppliersIgnoreErrors: true, + SuppliersMaxCost: "100", + CGREvent: cgrEv, + AttributeIDs: []string{"ATTR1", "ATTR2"}, + ThresholdIDs: []string{"ID1", "ID2"}, + StatIDs: []string{"test3", "test4"}, + } + rply = NewV1AuthorizeArgs(true, attributeIDs, false, thresholdIDs, true, statIDs, + false, true, true, true, false, cgrEv, nil, utils.Paginator{}, false, "100") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v,\n received: %+v", expected, rply) } @@ -928,6 +948,30 @@ func TestV1AuthorizeArgsParseFlags(t *testing.T) { if !reflect.DeepEqual(eOut, v1authArgs) { t.Errorf("Expecting %+v,\n received: %+v\n", utils.ToJSON(eOut), utils.ToJSON(v1authArgs)) } + + cgrArgs = v1authArgs.CGREvent.ExtractArgs(true, true) + eOut = &V1AuthorizeArgs{ + GetMaxUsage: true, + AuthorizeResources: true, + GetSuppliers: true, + SuppliersIgnoreErrors: true, + SuppliersMaxCost: "100", + GetAttributes: true, + AttributeIDs: []string{"Attr1", "Attr2"}, + ProcessThresholds: true, + ThresholdIDs: []string{"tr1", "tr2", "tr3"}, + ProcessStats: true, + StatIDs: []string{"st1", "st2", "st3"}, + ArgDispatcher: cgrArgs.ArgDispatcher, + Paginator: *cgrArgs.SupplierPaginator, + ForceDuration: true, + } + + strArg = "*accounts,*fd,*resources,,*dispatchers,*suppliers,*suppliers_ignore_errors,*suppliers_maxcost:100,*attributes:Attr1;Attr2,*thresholds:tr1;tr2;tr3,*stats:st1;st2;st3" + v1authArgs.ParseFlags(strArg) + if !reflect.DeepEqual(eOut, v1authArgs) { + t.Errorf("Expecting %+v,\n received: %+v\n", utils.ToJSON(eOut), utils.ToJSON(v1authArgs)) + } } func TestSessionSNewV1UpdateSessionArgs(t *testing.T) { @@ -1026,7 +1070,7 @@ func TestSessionSNewV1ProcessMessageArgs(t *testing.T) { GetSuppliers: true, } rply := NewV1ProcessMessageArgs(true, nil, false, nil, false, nil, - true, true, true, false, false, cgrEv, nil, utils.Paginator{}, false) + true, true, true, false, false, cgrEv, nil, utils.Paginator{}, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } @@ -1035,11 +1079,11 @@ func TestSessionSNewV1ProcessMessageArgs(t *testing.T) { GetAttributes: true, CGREvent: cgrEv, GetSuppliers: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, SuppliersIgnoreErrors: true, } rply = NewV1ProcessMessageArgs(true, nil, false, nil, false, nil, true, - false, true, true, true, cgrEv, nil, utils.Paginator{}, false) + false, true, true, true, cgrEv, nil, utils.Paginator{}, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } @@ -1053,18 +1097,34 @@ func TestSessionSNewV1ProcessMessageArgs(t *testing.T) { GetAttributes: true, CGREvent: cgrEv, GetSuppliers: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, SuppliersIgnoreErrors: true, AttributeIDs: []string{"ATTR1", "ATTR2"}, ThresholdIDs: []string{"ID1", "ID2"}, StatIDs: []string{"test3", "test4"}, } rply = NewV1ProcessMessageArgs(true, attributeIDs, false, thresholdIDs, false, statIDs, true, - false, true, true, true, cgrEv, nil, utils.Paginator{}, false) + false, true, true, true, cgrEv, nil, utils.Paginator{}, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } + expected = &V1ProcessMessageArgs{ + AllocateResources: true, + GetAttributes: true, + CGREvent: cgrEv, + GetSuppliers: true, + SuppliersMaxCost: "100", + SuppliersIgnoreErrors: true, + AttributeIDs: []string{"ATTR1", "ATTR2"}, + ThresholdIDs: []string{"ID1", "ID2"}, + StatIDs: []string{"test3", "test4"}, + } + rply = NewV1ProcessMessageArgs(true, attributeIDs, false, thresholdIDs, false, statIDs, true, + false, true, true, false, cgrEv, nil, utils.Paginator{}, false, "100") + if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } } func TestSessionSNewV1InitSessionArgs(t *testing.T) { @@ -1493,7 +1553,7 @@ func TestSessionSNewV1AuthorizeArgsWithArgDispatcher(t *testing.T) { } cgrArgs := cgrEv.ExtractArgs(true, true) rply := NewV1AuthorizeArgs(true, nil, false, nil, false, nil, true, false, false, false, - false, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false) + false, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rply)) } @@ -1505,7 +1565,7 @@ func TestSessionSNewV1AuthorizeArgsWithArgDispatcher(t *testing.T) { ProcessStats: true, GetSuppliers: false, SuppliersIgnoreErrors: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, CGREvent: cgrEv, ArgDispatcher: &utils.ArgDispatcher{ APIKey: utils.StringPointer("testkey"), @@ -1513,7 +1573,7 @@ func TestSessionSNewV1AuthorizeArgsWithArgDispatcher(t *testing.T) { }, } rply = NewV1AuthorizeArgs(true, nil, false, nil, true, nil, false, - true, false, true, true, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false) + true, false, true, true, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rply)) } @@ -1539,7 +1599,7 @@ func TestSessionSNewV1AuthorizeArgsWithArgDispatcher2(t *testing.T) { } cgrArgs := cgrEv.ExtractArgs(true, true) rply := NewV1AuthorizeArgs(true, nil, false, nil, false, nil, true, false, - false, false, false, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false) + false, false, false, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rply)) } @@ -1551,14 +1611,14 @@ func TestSessionSNewV1AuthorizeArgsWithArgDispatcher2(t *testing.T) { ProcessStats: true, GetSuppliers: false, SuppliersIgnoreErrors: true, - SuppliersMaxCost: utils.MetaSuppliersEventCost, + SuppliersMaxCost: utils.MetaEventCost, CGREvent: cgrEv, ArgDispatcher: &utils.ArgDispatcher{ RouteID: utils.StringPointer("testrouteid"), }, } rply = NewV1AuthorizeArgs(true, nil, false, nil, true, nil, false, - true, false, true, true, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false) + true, false, true, true, cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.SupplierPaginator, false, "") if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rply)) } @@ -1899,6 +1959,28 @@ func TestV1ProcessMessageArgsParseFlags(t *testing.T) { t.Errorf("Expecting %+v,\n received: %+v\n", utils.ToJSON(eOut), utils.ToJSON(v1ProcessMsgArgs)) } + cgrArgs = v1ProcessMsgArgs.CGREvent.ExtractArgs(true, true) + eOut = &V1ProcessMessageArgs{ + Debit: true, + AllocateResources: true, + GetSuppliers: true, + SuppliersIgnoreErrors: true, + SuppliersMaxCost: "100", + GetAttributes: true, + AttributeIDs: []string{"Attr1", "Attr2"}, + ProcessThresholds: true, + ThresholdIDs: []string{"tr1", "tr2", "tr3"}, + ProcessStats: true, + StatIDs: []string{"st1", "st2", "st3"}, + ArgDispatcher: cgrArgs.ArgDispatcher, + } + + strArg = "*accounts,*resources,*dispatchers,*suppliers,*suppliers_ignore_errors,*suppliers_maxcost:100,*attributes:Attr1;Attr2,*thresholds:tr1;tr2;tr3,*stats:st1;st2;st3" + v1ProcessMsgArgs.ParseFlags(strArg) + if !reflect.DeepEqual(eOut, v1ProcessMsgArgs) { + t.Errorf("Expecting %+v,\n received: %+v\n", utils.ToJSON(eOut), utils.ToJSON(v1ProcessMsgArgs)) + } + } func TestSessionSgetSession(t *testing.T) { diff --git a/utils/consts.go b/utils/consts.go index a43a68b85..e2d440cba 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -534,6 +534,8 @@ const ( MetaRound = "*round" Pong = "Pong" MetaEventCost = "*event_cost" + MetaSuppliersMaxCost = "*suppliers_maxcost" + MetaMaxCost = "*maxcost" MetaSuppliersEventCost = "*suppliers_event_cost" MetaSuppliersIgnoreErrors = "*suppliers_ignore_errors" Freeswitch = "freeswitch" diff --git a/utils/map.go b/utils/map.go index 9103cfc19..bd5aa6216 100644 --- a/utils/map.go +++ b/utils/map.go @@ -263,6 +263,14 @@ func (fWp FlagsWithParams) ParamsSlice(subs string) (ps []string) { return } +// ParamValue returns the value of the flag +func (fWp FlagsWithParams) ParamValue(subs string) (ps string) { + for _, ps = range fWp[subs] { + return + } + return +} + // SliceFlags converts from FlagsWithParams back to []string func (fWp FlagsWithParams) SliceFlags() (sls []string) { for key := range fWp { diff --git a/utils/map_test.go b/utils/map_test.go index dcdf57fd1..88860aa60 100644 --- a/utils/map_test.go +++ b/utils/map_test.go @@ -313,3 +313,21 @@ func TestFlagsWithParamsGetBool(t *testing.T) { t.Errorf("Expecting: true, received: %+v", ToJSON(rcv)) } } +func TestFlagsWithParamsValue(t *testing.T) { + flagsWithParams := &FlagsWithParams{ + "test": []string{"string2"}, + "empty": []string{}, + } + key := "notpresent" + if rcv := flagsWithParams.ParamValue(key); rcv != EmptyString { + t.Errorf("Expecting: %q, received: %+v", EmptyString, rcv) + } + key = "empty" + if rcv := flagsWithParams.ParamValue(key); rcv != EmptyString { + t.Errorf("Expecting: %q, received: %+v", EmptyString, rcv) + } + key = "test" + if rcv := flagsWithParams.ParamValue(key); rcv != "string2" { + t.Errorf("Expecting: string2, received: %+v", rcv) + } +}