Implement *force_disconnect_sessions action

This commit is contained in:
ionutboangiu
2024-03-06 14:49:24 -05:00
committed by Dan Christian Bogos
parent 03eff44767
commit 87db26b4ec
3 changed files with 78 additions and 19 deletions

View File

@@ -79,16 +79,20 @@ type ActionConnCfg struct {
}
func newActionConnCfg(source, action string, cfg *config.CGRConfig) ActionConnCfg {
sessionActions := []string{
utils.MetaAlterSessions,
utils.MetaForceDisconnectSessions,
}
act := ActionConnCfg{}
switch source {
case utils.ThresholdS:
switch action {
case utils.MetaAlterSessions:
switch {
case slices.Contains(sessionActions, action):
act.ConnIDs = cfg.ThresholdSCfg().SessionSConns
}
case utils.RALs:
switch action {
case utils.MetaAlterSessions:
switch {
case slices.Contains(sessionActions, action):
act.ConnIDs = cfg.RalsCfg().SessionSConns
}
}
@@ -124,6 +128,7 @@ func init() {
actionFuncMap[utils.MetaTransferMonetaryDefault] = transferMonetaryDefaultAction
actionFuncMap[utils.MetaCgrRpc] = cgrRPCAction
actionFuncMap[utils.MetaAlterSessions] = alterSessionsAction
actionFuncMap[utils.MetaForceDisconnectSessions] = forceDisconnectSessionsAction
actionFuncMap[utils.TopUpZeroNegative] = topupZeroNegativeAction
actionFuncMap[utils.SetExpiry] = setExpiryAction
actionFuncMap[utils.MetaPublishAccount] = publishAccount
@@ -944,6 +949,50 @@ func alterSessionsAction(_ *Account, act *Action, _ Actions, _ *FilterS, _ any,
return connMgr.Call(context.Background(), connCfg.ConnIDs, utils.SessionSv1AlterSessions, attr, &reply)
}
// forceDisconnectSessionsAction processes the `ExtraParameters` field from the action to construct a request
// for the `SessionSv1.ForceDisconnect` API call.
//
// The ExtraParameters field format is expected as follows:
// - tenant: string
// - filters: strings separated by "&".
// - limit: integer, specifying the maximum number of sessions to disconnect.
// - APIOpts: set of key-value pairs (separated by "&").
// - Event: set of key-value pairs (separated by "&").
//
// Parameters are separated by ";" and must be provided in the specified order.
func forceDisconnectSessionsAction(_ *Account, act *Action, _ Actions, _ *FilterS, _ any, connCfg ActionConnCfg) (err error) {
// Parse action parameters based on the predefined format.
params := strings.Split(act.ExtraParameters, ";")
if len(params) != 5 {
return errors.New("invalid number of parameters; expected 5")
}
// If conversion fails, limit will default to 0.
limit, _ := strconv.Atoi(params[2])
// Prepare request arguments based on provided parameters.
attr := utils.SessionFilterWithEvent{
SessionFilter: &utils.SessionFilter{
Limit: &limit,
Tenant: params[0],
Filters: strings.Split(params[1], "&"),
APIOpts: make(map[string]any),
},
Event: make(map[string]any),
}
if err := parseParamStringToMap(params[3], attr.APIOpts); err != nil {
return err
}
if err := parseParamStringToMap(params[4], attr.Event); err != nil {
return err
}
var reply string
return connMgr.Call(context.Background(), connCfg.ConnIDs, utils.SessionSv1ForceDisconnect, attr, &reply)
}
// parseParamStringToMap parses a string containing key-value pairs separated by "&" and assigns
// these pairs to a given map. Each pair is expected to be in the format "key:value".
func parseParamStringToMap(paramStr string, targetMap map[string]any) error {

View File

@@ -4576,21 +4576,17 @@ func TestActionsTransferBalance(t *testing.T) {
}
}
type mockSessionSv1Obj struct {
request string
}
func (m *mockSessionSv1Obj) AlterSessions(_ *context.Context, params utils.SessionFilterWithEvent, reply *string) error {
m.request = utils.ToJSON(params)
return nil
}
func TestActionsAlterSessions(t *testing.T) {
var receivedRequest string
func TestActionsAlterAndDisconnectSessions(t *testing.T) {
var alterSessionsRequest string
var disconnectSessionsRequest string
ccMock := &ccMock{
calls: map[string]func(ctx *context.Context, args any, reply any) error{
utils.SessionSv1AlterSessions: func(ctx *context.Context, args, reply any) error {
receivedRequest = utils.ToJSON(args)
alterSessionsRequest = utils.ToJSON(args)
return nil
},
utils.SessionSv1ForceDisconnect: func(ctx *context.Context, args, reply any) error {
disconnectSessionsRequest = utils.ToJSON(args)
return nil
},
},
@@ -4641,7 +4637,8 @@ func TestActionsAlterSessions(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
action := &Action{ExtraParameters: tc.extraParams}
t.Cleanup(func() {
receivedRequest = ""
alterSessionsRequest = ""
disconnectSessionsRequest = ""
})
err := alterSessionsAction(nil, action, nil, nil, nil, ActionConnCfg{
ConnIDs: tc.connIDs,
@@ -4652,8 +4649,20 @@ func TestActionsAlterSessions(t *testing.T) {
}
} else if err != nil {
t.Error(err)
} else if receivedRequest != tc.expectedRequest {
t.Errorf("expected: %v\nreceived: %v", tc.expectedRequest, receivedRequest)
} else if alterSessionsRequest != tc.expectedRequest {
t.Errorf("expected: %v\nreceived: %v", tc.expectedRequest, alterSessionsRequest)
}
err = forceDisconnectSessionsAction(nil, action, nil, nil, nil, ActionConnCfg{
ConnIDs: tc.connIDs,
})
if tc.expectedErr != "" {
if err == nil || err.Error() != tc.expectedErr {
t.Errorf("expected error %v, received %v", tc.expectedErr, err)
}
} else if err != nil {
t.Error(err)
} else if disconnectSessionsRequest != tc.expectedRequest {
t.Errorf("expected: %v\nreceived: %v", tc.expectedRequest, disconnectSessionsRequest)
}
})
}

View File

@@ -1061,6 +1061,7 @@ const (
MetaTransferMonetaryDefault = "*transfer_monetary_default"
MetaCgrRpc = "*cgr_rpc"
MetaAlterSessions = "*alter_sessions"
MetaForceDisconnectSessions = "*force_disconnect_sessions"
TopUpZeroNegative = "*topup_zero_negative"
SetExpiry = "*set_expiry"
MetaPublishAccount = "*publish_account"