diff --git a/apier/v1/api_interfaces.go b/apier/v1/api_interfaces.go
index bf11a25cd..891eea282 100644
--- a/apier/v1/api_interfaces.go
+++ b/apier/v1/api_interfaces.go
@@ -174,6 +174,7 @@ type ConfigSv1Interface interface {
type CoreSv1Interface interface {
Status(arg *utils.TenantWithOpts, reply *map[string]interface{}) error
Ping(ign *utils.CGREventWithOpts, reply *string) error
+ Sleep(arg *utils.DurationArgs, reply *string) error
}
type RateSv1Interface interface {
diff --git a/apier/v1/concreqs_it_test.go b/apier/v1/concreqs_it_test.go
index cf9ef0283..b10bba647 100644
--- a/apier/v1/concreqs_it_test.go
+++ b/apier/v1/concreqs_it_test.go
@@ -93,7 +93,7 @@ func testConcReqsStartEngine(t *testing.T) {
}
}
-func handlePing(clnt *rpc2.Client, arg *DurationArgs, reply *string) error {
+func handlePing(clnt *rpc2.Client, arg *utils.DurationArgs, reply *string) error {
time.Sleep(arg.DurationTime)
*reply = utils.OK
return nil
@@ -124,7 +124,7 @@ func testConcReqsBusyAPIs(t *testing.T) {
go func() {
var resp string
if err := concReqsRPC.Call(utils.CoreSv1Sleep,
- &DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
+ &utils.DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
&resp); err != nil {
lock.Lock()
failedAPIs++
@@ -151,7 +151,7 @@ func testConcReqsQueueAPIs(t *testing.T) {
go func() {
var resp string
if err := concReqsRPC.Call(utils.CoreSv1Sleep,
- &DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
+ &utils.DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
&resp); err != nil {
wg.Done()
t.Error(err)
@@ -234,7 +234,7 @@ func testConcReqsOnBiJSONBusy(t *testing.T) {
go func() {
var resp string
if err := concReqsBiRPC.Call(utils.SessionSv1Sleep,
- &DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
+ &utils.DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
&resp); err != nil {
lock.Lock()
failedAPIs++
@@ -261,7 +261,7 @@ func testConcReqsOnBiJSONQueue(t *testing.T) {
go func() {
var resp string
if err := concReqsBiRPC.Call(utils.SessionSv1Sleep,
- &DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
+ &utils.DurationArgs{DurationTime: time.Duration(10 * time.Millisecond)},
&resp); err != nil {
wg.Done()
t.Error(err)
diff --git a/apier/v1/core.go b/apier/v1/core.go
index 6ad93c322..5010c50a3 100644
--- a/apier/v1/core.go
+++ b/apier/v1/core.go
@@ -50,12 +50,8 @@ func (cS *CoreSv1) Ping(ign *utils.CGREventWithOpts, reply *string) error {
return nil
}
-type DurationArgs struct {
- DurationTime time.Duration
-}
-
// Sleep is used to test the concurrent requests mechanism
-func (cS *CoreSv1) Sleep(arg *DurationArgs, reply *string) error {
+func (cS *CoreSv1) Sleep(arg *utils.DurationArgs, reply *string) error {
time.Sleep(arg.DurationTime)
*reply = utils.OK
return nil
diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go
index 83e783442..93047b1bd 100755
--- a/apier/v1/dispatcher.go
+++ b/apier/v1/dispatcher.go
@@ -34,11 +34,11 @@ func (apierSv1 *APIerSv1) GetDispatcherProfile(arg *utils.TenantID, reply *engin
if missing := utils.MissingStructFields(arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
- if dpp, err := apierSv1.DataManager.GetDispatcherProfile(arg.Tenant, arg.ID, true, true, utils.NonTransactional); err != nil {
+ dpp, err := apierSv1.DataManager.GetDispatcherProfile(arg.Tenant, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
return utils.APIErrorHandler(err)
- } else {
- *reply = *dpp
}
+ *reply = *dpp
return nil
}
@@ -124,11 +124,11 @@ func (apierSv1 *APIerSv1) GetDispatcherHost(arg *utils.TenantID, reply *engine.D
if missing := utils.MissingStructFields(arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
- if dpp, err := apierSv1.DataManager.GetDispatcherHost(arg.Tenant, arg.ID, true, false, utils.NonTransactional); err != nil {
+ dpp, err := apierSv1.DataManager.GetDispatcherHost(arg.Tenant, arg.ID, true, false, utils.NonTransactional)
+ if err != nil {
return utils.APIErrorHandler(err)
- } else {
- *reply = *dpp
}
+ *reply = *dpp
return nil
}
@@ -841,6 +841,10 @@ func (dS *DispatcherCoreSv1) Ping(args *utils.CGREventWithOpts, reply *string) e
return dS.dS.CoreSv1Ping(args, reply)
}
+func (dS *DispatcherCoreSv1) Sleep(arg *utils.DurationArgs, reply *string) error {
+ return dS.dS.CoreSv1Sleep(arg, reply)
+}
+
func NewDispatcherRALsV1(dps *dispatchers.DispatcherService) *DispatcherRALsV1 {
return &DispatcherRALsV1{dS: dps}
}
diff --git a/apier/v1/sessionsbirpc.go b/apier/v1/sessionsbirpc.go
index f66c37efd..5a2a4b0ee 100644
--- a/apier/v1/sessionsbirpc.go
+++ b/apier/v1/sessionsbirpc.go
@@ -303,7 +303,7 @@ func (ssv1 *SessionSv1) BiRPCV1STIRIdentity(clnt *rpc2.Client,
return ssv1.Ss.BiRPCv1STIRIdentity(nil, args, reply)
}
-func (ssv1 *SessionSv1) BiRPCV1Sleep(clnt *rpc2.Client, arg *DurationArgs,
+func (ssv1 *SessionSv1) BiRPCV1Sleep(clnt *rpc2.Client, arg *utils.DurationArgs,
reply *string) (err error) {
if err = utils.ConReqs.Allocate(); err != nil {
return
diff --git a/data/tariffplans/dispatchers/Attributes.csv b/data/tariffplans/dispatchers/Attributes.csv
index 0d9a32508..9d2a52072 100644
--- a/data/tariffplans/dispatchers/Attributes.csv
+++ b/data/tariffplans/dispatchers/Attributes.csv
@@ -23,3 +23,4 @@ cgrates.org,ATTR_API_RALS_AUTH,*auth,*string:~*req.ApiKey:rals12345,,,*req.APIMe
cgrates.org,ATTR_API_REPLICATOR_AUTH,*auth,*string:~*req.ApiKey:repl12345,,,*req.APIMethods,*constant,ReplicatorSv1.Ping&ReplicatorSv1.GetAccount&ReplicatorSv1.SetAccount&ReplicatorSv1.RemoveAccount&ReplicatorSv1.GetRouteProfile&ReplicatorSv1.SetRouteProfile&ReplicatorSv1.RemoveRouteProfile&ReplicatorSv1.GetAttributeProfile&ReplicatorSv1.SetAttributeProfile&ReplicatorSv1.RemoveAttributeProfile&ReplicatorSv1.SetChargerProfile&ReplicatorSv1.GetChargerProfile&ReplicatorSv1.RemoveChargerProfile&ReplicatorSv1.GetDispatcherProfile&ReplicatorSv1.SetDispatcherProfile&ReplicatorSv1.RemoveDispatcherProfile&ReplicatorSv1.GetDispatcherHost&ReplicatorSv1.SetDispatcherHost&ReplicatorSv1.RemoveDispatcherHost&ReplicatorSv1.GetFilter&ReplicatorSv1.SetFilter&ReplicatorSv1.RemoveFilter&ReplicatorSv1.GetThreshold&ReplicatorSv1.SetThreshold&ReplicatorSv1.RemoveThreshold&ReplicatorSv1.GetStatQueue&ReplicatorSv1.SetStatQueue&ReplicatorSv1.RemoveStatQueue&ReplicatorSv1.GetResource&ReplicatorSv1.SetResource&ReplicatorSv1.RemoveResource&ReplicatorSv1.GetResourceProfile&ReplicatorSv1.SetResourceProfile&ReplicatorSv1.RemoveResourceProfile&ReplicatorSv1.GetStatQueueProfile&ReplicatorSv1.SetStatQueueProfile&ReplicatorSv1.RemoveStatQueueProfile&ReplicatorSv1.GetThresholdProfile&ReplicatorSv1.SetThresholdProfile&ReplicatorSv1.RemoveThresholdProfile&ReplicatorSv1.GetTiming&ReplicatorSv1.SetTiming&ReplicatorSv1.RemoveTiming&ReplicatorSv1.GetActionTriggers&ReplicatorSv1.SetActionTriggers&ReplicatorSv1.RemoveActionTriggers&ReplicatorSv1.SetSharedGroup&ReplicatorSv1.GetSharedGroup&ReplicatorSv1.RemoveSharedGroup&ReplicatorSv1.SetActions&ReplicatorSv1.GetActions&ReplicatorSv1.RemoveActions&ReplicatorSv1.SetActionPlan&ReplicatorSv1.GetActionPlan&ReplicatorSv1.RemoveActionPlan&ReplicatorSv1.SetAccountActionPlans&ReplicatorSv1.GetAccountActionPlans&ReplicatorSv1.RemAccountActionPlans&ReplicatorSv1.SetRatingPlan&ReplicatorSv1.GetRatingPlan&ReplicatorSv1.RemoveRatingPlan&ReplicatorSv1.SetRatingProfile&ReplicatorSv1.GetRatingProfile&ReplicatorSv1.RemoveRatingProfile&ReplicatorSv1.SetDestination&ReplicatorSv1.GetDestination&ReplicatorSv1.RemoveDestination&ReplicatorSv1.SetLoadIDs&ReplicatorSv1.GetItemLoadIDs&ReplicatorSv1.SetRateProfile&ReplicatorSv1.GetRateProfile&ReplicatorSv1.RemoveRateProfile,false,20
cgrates.org,ATTR_API_CDRSV2,*auth,*string:~*req.ApiKey:cdrsv212345,,,*req.APIMethods,*constant,CDRsV2.ProcessEvent&CDRsV2.StoreSessionCost,false,20
cgrates.org,ATTR_API_RATES_AUTH,*auth,*string:~*req.ApiKey:rPrf12345,,,*req.APIMethods,*constant,RateSv1.Ping,false,20
+cgrates.org,ATTR_API_CORE_AUTH,*auth,*string:~*req.ApiKey:core12345,,,*req.APIMethods,*constant,CoreSv1.Status&CoreSv1.Ping&CoreSv1.Sleep,false,20
\ No newline at end of file
diff --git a/data/tariffplans/dispatchers/DispatcherProfiles.csv b/data/tariffplans/dispatchers/DispatcherProfiles.csv
index f256020cb..5214c0e2f 100644
--- a/data/tariffplans/dispatchers/DispatcherProfiles.csv
+++ b/data/tariffplans/dispatchers/DispatcherProfiles.csv
@@ -12,4 +12,6 @@ cgrates.org,EVENT3,,,,,,ALL,,10,,,
cgrates.org,EVENT4,*any,*string:~*req.EventName:Broadcast,,*broadcast,,ALL2,,20,false,,20
cgrates.org,EVENT4,,,,,,ALL,,10,,,
cgrates.org,EVENT5,*any,*string:~*req.EventName:Internal,,*weight,,SELF,,20,false,,20
-cgrates.org,EVENT6,*any,*string:~*opts.*method:DispatcherSv1.GetProfileForEvent,,*weight,,SELF,,20,false,,20
\ No newline at end of file
+cgrates.org,EVENT6,*any,*string:~*opts.*method:DispatcherSv1.GetProfileForEvent,,*weight,,SELF,,20,false,,20
+cgrates.org,EVENT7,*any,*string:~*opts.EventType:LoadDispatcher,,*weight,,ALL,,20,false,,207
+cgrates.org,EVENT7,*any,,,*weight,,ALL2,,20,false,*ratio:1,207
\ No newline at end of file
diff --git a/data/tariffplans/dispatchers_gob/Attributes.csv b/data/tariffplans/dispatchers_gob/Attributes.csv
index 0d9a32508..1a8b4574a 100644
--- a/data/tariffplans/dispatchers_gob/Attributes.csv
+++ b/data/tariffplans/dispatchers_gob/Attributes.csv
@@ -23,3 +23,4 @@ cgrates.org,ATTR_API_RALS_AUTH,*auth,*string:~*req.ApiKey:rals12345,,,*req.APIMe
cgrates.org,ATTR_API_REPLICATOR_AUTH,*auth,*string:~*req.ApiKey:repl12345,,,*req.APIMethods,*constant,ReplicatorSv1.Ping&ReplicatorSv1.GetAccount&ReplicatorSv1.SetAccount&ReplicatorSv1.RemoveAccount&ReplicatorSv1.GetRouteProfile&ReplicatorSv1.SetRouteProfile&ReplicatorSv1.RemoveRouteProfile&ReplicatorSv1.GetAttributeProfile&ReplicatorSv1.SetAttributeProfile&ReplicatorSv1.RemoveAttributeProfile&ReplicatorSv1.SetChargerProfile&ReplicatorSv1.GetChargerProfile&ReplicatorSv1.RemoveChargerProfile&ReplicatorSv1.GetDispatcherProfile&ReplicatorSv1.SetDispatcherProfile&ReplicatorSv1.RemoveDispatcherProfile&ReplicatorSv1.GetDispatcherHost&ReplicatorSv1.SetDispatcherHost&ReplicatorSv1.RemoveDispatcherHost&ReplicatorSv1.GetFilter&ReplicatorSv1.SetFilter&ReplicatorSv1.RemoveFilter&ReplicatorSv1.GetThreshold&ReplicatorSv1.SetThreshold&ReplicatorSv1.RemoveThreshold&ReplicatorSv1.GetStatQueue&ReplicatorSv1.SetStatQueue&ReplicatorSv1.RemoveStatQueue&ReplicatorSv1.GetResource&ReplicatorSv1.SetResource&ReplicatorSv1.RemoveResource&ReplicatorSv1.GetResourceProfile&ReplicatorSv1.SetResourceProfile&ReplicatorSv1.RemoveResourceProfile&ReplicatorSv1.GetStatQueueProfile&ReplicatorSv1.SetStatQueueProfile&ReplicatorSv1.RemoveStatQueueProfile&ReplicatorSv1.GetThresholdProfile&ReplicatorSv1.SetThresholdProfile&ReplicatorSv1.RemoveThresholdProfile&ReplicatorSv1.GetTiming&ReplicatorSv1.SetTiming&ReplicatorSv1.RemoveTiming&ReplicatorSv1.GetActionTriggers&ReplicatorSv1.SetActionTriggers&ReplicatorSv1.RemoveActionTriggers&ReplicatorSv1.SetSharedGroup&ReplicatorSv1.GetSharedGroup&ReplicatorSv1.RemoveSharedGroup&ReplicatorSv1.SetActions&ReplicatorSv1.GetActions&ReplicatorSv1.RemoveActions&ReplicatorSv1.SetActionPlan&ReplicatorSv1.GetActionPlan&ReplicatorSv1.RemoveActionPlan&ReplicatorSv1.SetAccountActionPlans&ReplicatorSv1.GetAccountActionPlans&ReplicatorSv1.RemAccountActionPlans&ReplicatorSv1.SetRatingPlan&ReplicatorSv1.GetRatingPlan&ReplicatorSv1.RemoveRatingPlan&ReplicatorSv1.SetRatingProfile&ReplicatorSv1.GetRatingProfile&ReplicatorSv1.RemoveRatingProfile&ReplicatorSv1.SetDestination&ReplicatorSv1.GetDestination&ReplicatorSv1.RemoveDestination&ReplicatorSv1.SetLoadIDs&ReplicatorSv1.GetItemLoadIDs&ReplicatorSv1.SetRateProfile&ReplicatorSv1.GetRateProfile&ReplicatorSv1.RemoveRateProfile,false,20
cgrates.org,ATTR_API_CDRSV2,*auth,*string:~*req.ApiKey:cdrsv212345,,,*req.APIMethods,*constant,CDRsV2.ProcessEvent&CDRsV2.StoreSessionCost,false,20
cgrates.org,ATTR_API_RATES_AUTH,*auth,*string:~*req.ApiKey:rPrf12345,,,*req.APIMethods,*constant,RateSv1.Ping,false,20
+cgrates.org,ATTR_API_CORE_AUTH,*auth,*string:~*req.ApiKey:core12345,,,*req.APIMethods,*constant,CoreSv1.Status&CoreSv1.Ping&CoreSv1.Sleep,false,20
diff --git a/data/tariffplans/dispatchers_gob/DispatcherProfiles.csv b/data/tariffplans/dispatchers_gob/DispatcherProfiles.csv
index 224651a12..5214c0e2f 100644
--- a/data/tariffplans/dispatchers_gob/DispatcherProfiles.csv
+++ b/data/tariffplans/dispatchers_gob/DispatcherProfiles.csv
@@ -12,3 +12,6 @@ cgrates.org,EVENT3,,,,,,ALL,,10,,,
cgrates.org,EVENT4,*any,*string:~*req.EventName:Broadcast,,*broadcast,,ALL2,,20,false,,20
cgrates.org,EVENT4,,,,,,ALL,,10,,,
cgrates.org,EVENT5,*any,*string:~*req.EventName:Internal,,*weight,,SELF,,20,false,,20
+cgrates.org,EVENT6,*any,*string:~*opts.*method:DispatcherSv1.GetProfileForEvent,,*weight,,SELF,,20,false,,20
+cgrates.org,EVENT7,*any,*string:~*opts.EventType:LoadDispatcher,,*weight,,ALL,,20,false,,207
+cgrates.org,EVENT7,*any,,,*weight,,ALL2,,20,false,*ratio:1,207
\ No newline at end of file
diff --git a/dispatchers/core.go b/dispatchers/core.go
index 53852b44d..05e008cd0 100644
--- a/dispatchers/core.go
+++ b/dispatchers/core.go
@@ -57,3 +57,23 @@ func (dS *DispatcherService) CoreSv1Ping(args *utils.CGREventWithOpts, reply *st
}
return dS.Dispatch(args, utils.MetaCore, utils.CoreSv1Ping, args, reply)
}
+
+func (dS *DispatcherService) CoreSv1Sleep(args *utils.DurationArgs,
+ reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args.TenantArg != nil && args.TenantArg.Tenant != utils.EmptyString {
+ tnt = args.TenantArg.Tenant
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1Sleep, tnt,
+ utils.IfaceAsString(args.Opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREventWithOpts{
+ CGREvent: &utils.CGREvent{
+ Tenant: tnt,
+ },
+ Opts: args.Opts,
+ }, utils.MetaCore, utils.CoreSv1Sleep, args, reply)
+}
diff --git a/dispatchers/core_it_test.go b/dispatchers/core_it_test.go
new file mode 100644
index 000000000..8b835a482
--- /dev/null
+++ b/dispatchers/core_it_test.go
@@ -0,0 +1,113 @@
+// +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 dispatchers
+
+import (
+ "net/rpc"
+ "testing"
+ "time"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+var sTestsDspCore = []func(t *testing.T){
+ testDspCoreLoad,
+}
+
+//Test start here
+func TestDspCoreIT(t *testing.T) {
+ var config1, config2, config3 string
+ switch *dbType {
+ case utils.MetaInternal:
+ t.SkipNow()
+ case utils.MetaMySQL:
+ config1 = "all_mysql"
+ config2 = "all2_mysql"
+ config3 = "dispatchers_mysql"
+ case utils.MetaMongo:
+ config1 = "all_mongo"
+ config2 = "all2_mongo"
+ config3 = "dispatchers_mongo"
+ case utils.MetaPostgres:
+ t.SkipNow()
+ default:
+ t.Fatal("Unknown Database type")
+ }
+
+ dispDIR := "dispatchers"
+ if *encoding == utils.MetaGOB {
+ dispDIR += "_gob"
+ }
+ testDsp(t, sTestsDspCore, "TestDspCoreIT", config1, config2, config3, "tutorial", "oldtutorial", dispDIR)
+}
+
+func testDspCoreLoad(t *testing.T) {
+ var status map[string]interface{}
+ statusTnt := utils.TenantWithOpts{
+ TenantArg: &utils.TenantArg{
+ Tenant: "cgrates.org",
+ },
+ Opts: map[string]interface{}{
+ utils.OptsAPIKey: "core12345",
+ utils.OptsRouteID: "core1",
+ "EventType": "LoadDispatcher",
+ },
+ }
+ expNodeID := "ALL"
+ if err := dispEngine.RPC.Call(utils.CoreSv1Status, statusTnt, &status); err != nil {
+ t.Error(err)
+ } else if status[utils.NodeID] == "ALL2" {
+ expNodeID = "ALL2"
+ }
+ dur := &utils.DurationArgs{
+ DurationTime: 500 * time.Millisecond,
+ TenantArg: &utils.TenantArg{
+ Tenant: "cgrates.org",
+ },
+ Opts: map[string]interface{}{
+ utils.OptsAPIKey: "core12345",
+ utils.OptsRouteID: "core1",
+ "EventType": "LoadDispatcher",
+ },
+ }
+ var rply string
+ statusTnt2 := utils.TenantWithOpts{
+ TenantArg: &utils.TenantArg{
+ Tenant: "cgrates.org",
+ },
+ Opts: map[string]interface{}{
+ utils.OptsAPIKey: "core12345",
+ "EventType": "LoadDispatcher",
+ },
+ }
+ call := dispEngine.RPC.Go(utils.CoreSv1Sleep, dur, &rply, make(chan *rpc.Call, 1))
+ if err := dispEngine.RPC.Call(utils.CoreSv1Status, statusTnt2, &status); err != nil {
+ t.Error(err)
+ } else if status[utils.NodeID] != expNodeID {
+ t.Errorf("Expected status to be called on node <%s> but it was called on <%s>", expNodeID, status[utils.NodeID])
+ }
+ if ans := <-call.Done; ans.Error != nil {
+ t.Fatal(ans.Error)
+ } else if rply != utils.OK {
+ t.Errorf("Expected: %q ,received: %q", utils.OK, rply)
+ }
+
+}
diff --git a/dispatchers/libdispatcher_test.go b/dispatchers/libdispatcher_test.go
index b21359ef7..23dbb601f 100644
--- a/dispatchers/libdispatcher_test.go
+++ b/dispatchers/libdispatcher_test.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package dispatchers
import (
+ "reflect"
"testing"
"github.com/cgrates/cgrates/engine"
@@ -59,3 +60,33 @@ func TestLoadMetricsGetHosts(t *testing.T) {
t.Errorf("Expected: %q ,received: %q", "DSP_2", rply[0])
}
}
+
+func TestNewSingleStrategyDispatcher(t *testing.T) {
+ dhp := engine.DispatcherHostProfiles{
+ {ID: "DSP_1"},
+ {ID: "DSP_2"},
+ {ID: "DSP_3"},
+ {ID: "DSP_4"},
+ {ID: "DSP_5"},
+ }
+ var exp strategyDispatcher = new(singleResultstrategyDispatcher)
+ if rply := newSingleStrategyDispatcher(dhp, utils.EmptyString); !reflect.DeepEqual(exp, rply) {
+ t.Errorf("Expected: singleResultstrategyDispatcher structure,received: %s", utils.ToJSON(rply))
+ }
+
+ dhp = engine.DispatcherHostProfiles{
+ {ID: "DSP_1"},
+ {ID: "DSP_2"},
+ {ID: "DSP_3"},
+ {ID: "DSP_4"},
+ {ID: "DSP_5", Params: map[string]interface{}{utils.MetaRatio: 1}},
+ }
+ exp = &loadStrategyDispatcher{
+ hosts: dhp,
+ tntID: "cgrates.org",
+ }
+ if rply := newSingleStrategyDispatcher(dhp, "cgrates.org"); !reflect.DeepEqual(exp, rply) {
+ t.Errorf("Expected: loadStrategyDispatcher structure,received: %s", utils.ToJSON(rply))
+
+ }
+}
diff --git a/utils/coreutils.go b/utils/coreutils.go
index 0d9e38443..20dfc12ff 100644
--- a/utils/coreutils.go
+++ b/utils/coreutils.go
@@ -940,3 +940,9 @@ type SetIndexesArg struct {
TenantArg
Opts map[string]interface{}
}
+
+type DurationArgs struct {
+ DurationTime time.Duration
+ Opts map[string]interface{}
+ *TenantArg
+}