From a8a68a418e51bab7d8bbf4b92946e2e2570d6933 Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Mon, 2 May 2022 19:36:52 +0300 Subject: [PATCH] Implement ActionBlockers +tests (not properly implemented) --- actions/actions.go | 7 + apis/actions_it_test.go | 165 +++++++++++++++++- .../samples/apis_actions_mysql/cgrates.json | 23 +-- 3 files changed, 179 insertions(+), 16 deletions(-) diff --git a/actions/actions.go b/actions/actions.go index 27791dbfa..264cedb0d 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -231,6 +231,13 @@ func (aS *ActionS) scheduledActions(ctx *context.Context, tnt string, cgrEv *uti trgTyp := actionTarget(aCfg.Type) trgActs[trgTyp] = append(trgActs[trgTyp], act) } + var blocker bool + if blocker, err = engine.BlockerFromDynamics(ctx, aCfg.Blockers, aS.fltrS, tnt, evNm); err != nil { + return + } + if blocker { + break + } } if partExec { continue // skip this profile from processing further diff --git a/apis/actions_it_test.go b/apis/actions_it_test.go index 2c7751837..1b8d7fc65 100644 --- a/apis/actions_it_test.go +++ b/apis/actions_it_test.go @@ -87,11 +87,16 @@ var ( testActionsRemoveActionProfile, testActionsGetActionProfileAfterRemove, - // blocker behaviour test + // ActionProfile blocker behaviour test testActionsRemoveActionProfiles, testActionsSetActionProfiles, testActionsExecuteActions, + // APAction blocker behaviour test + testActionsBlockerSetAccount, + testActionsBlockerSetActionProfile, + testActionsBlockerExecuteActions, + testActionsKillEngine, } ) @@ -699,7 +704,7 @@ func testActionsSetActionProfiles(t *testing.T) { ActionProfile: &engine.ActionProfile{ ID: "ACTION_TEST_1", Tenant: "cgrates.org", - FilterIDs: []string{"*string:~*req.TestCase:BlockerBehaviour"}, + FilterIDs: []string{"*string:~*req.TestCase:ActionProfileBlockerBehaviour"}, Weights: utils.DynamicWeights{ { Weight: 30, @@ -723,7 +728,7 @@ func testActionsSetActionProfiles(t *testing.T) { ActionProfile: &engine.ActionProfile{ ID: "ACTION_TEST_2", Tenant: "cgrates.org", - FilterIDs: []string{"*string:~*req.TestCase:BlockerBehaviour"}, + FilterIDs: []string{"*string:~*req.TestCase:ActionProfileBlockerBehaviour"}, Weights: utils.DynamicWeights{ { Weight: 10, @@ -742,7 +747,7 @@ func testActionsSetActionProfiles(t *testing.T) { ActionProfile: &engine.ActionProfile{ ID: "ACTION_TEST_3", Tenant: "cgrates.org", - FilterIDs: []string{"*string:~*req.TestCase:BlockerBehaviour"}, + FilterIDs: []string{"*string:~*req.TestCase:ActionProfileBlockerBehaviour"}, Weights: utils.DynamicWeights{ { Weight: 20, @@ -766,7 +771,7 @@ func testActionsSetActionProfiles(t *testing.T) { ActionProfile: &engine.ActionProfile{ ID: "ACTION_TEST_4", Tenant: "cgrates.org", - FilterIDs: []string{"*string:~*req.TestCase:BlockerBehaviour"}, + FilterIDs: []string{"*string:~*req.TestCase:ActionProfileBlockerBehaviour"}, Weights: utils.DynamicWeights{ { Weight: 5, @@ -799,7 +804,7 @@ func testActionsExecuteActions(t *testing.T) { Tenant: "cgrates.org", ID: "EventExecuteActions", Event: map[string]interface{}{ - "TestCase": "BlockerBehaviour", + "TestCase": "ActionProfileBlockerBehaviour", }, APIOpts: map[string]interface{}{}, } @@ -810,3 +815,151 @@ func testActionsExecuteActions(t *testing.T) { t.Error("Unexpected reply returned:", reply) } } + +func testActionsBlockerSetAccount(t *testing.T) { + args := &utils.AccountWithAPIOpts{ + Account: &utils.Account{ + Tenant: "cgrates.org", + ID: "ACCOUNT_BLOCKER_TEST", + Opts: map[string]interface{}{}, + Balances: map[string]*utils.Balance{ + "BALANCE_TEST": { + ID: "BALANCE_TEST", + FilterIDs: []string{"*string:~*req.TestCase:ActionBlockerBehaviour"}, + Weights: utils.DynamicWeights{ + { + Weight: 12, + }, + }, + Type: utils.MetaConcrete, + Units: utils.NewDecimal(0, 0), + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + var reply string + if err := actRPC.Call(context.Background(), utils.AdminSv1SetAccount, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } +} + +func testActionsBlockerSetActionProfile(t *testing.T) { + actionProfile := &engine.ActionProfileWithAPIOpts{ + ActionProfile: &engine.ActionProfile{ + ID: "ACTION_BLOCKER_TEST", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.TestCase:ActionBlockerBehaviour"}, + Weights: utils.DynamicWeights{ + { + Weight: 30, + }, + }, + Blockers: utils.Blockers{ + { + Blocker: false, + }, + }, + Targets: map[string]utils.StringSet{ + utils.MetaAccounts: { + "ACCOUNT_BLOCKER_TEST": struct{}{}, + }, + }, + Actions: []*engine.APAction{ + { + ID: "action1", + Type: utils.MetaAddBalance, + Diktats: []*engine.APDiktat{ + { + // Path: "~*accounts.ACCOUNT_BLOCKER_TEST.Balances[BALANCE_TEST].Units", + Path: "*balance.BALANCE_TEST.Units", + Value: "1", + }, + }, + }, + { + ID: "action2", + Type: utils.MetaAddBalance, + Diktats: []*engine.APDiktat{ + { + Path: "*balance.BALANCE_TEST.Units", + Value: "2", + }, + }, + Blockers: utils.Blockers{ + { + Blocker: true, + }, + }, + }, + { + ID: "action3", + Type: utils.MetaAddBalance, + Diktats: []*engine.APDiktat{ + { + Path: "*balance.BALANCE_TEST.Units", + Value: "3", + }, + }, + }, + { + ID: "action4", + Type: utils.MetaAddBalance, + Diktats: []*engine.APDiktat{ + { + Path: "*balance.BALANCE_TEST.Units", + Value: "4", + }, + }, + }, + }, + }, + } + + var reply string + if err := actRPC.Call(context.Background(), utils.AdminSv1SetActionProfile, + actionProfile, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } +} + +func testActionsBlockerExecuteActions(t *testing.T) { + args := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EventExecuteActions", + Event: map[string]interface{}{ + "TestCase": "ActionBlockerBehaviour", + }, + APIOpts: map[string]interface{}{}, + } + var reply string + if err := actRPC.Call(context.Background(), utils.ActionSv1ExecuteActions, args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned:", reply) + } + + argsGet := &utils.TenantIDWithAPIOpts{ + TenantID: &utils.TenantID{ + Tenant: "cgrates.org", + ID: "ACCOUNT_BLOCKER_TEST", + }, + } + + var replyAcc utils.Account + if err := actRPC.Call(context.Background(), utils.AdminSv1GetAccount, argsGet, &replyAcc); err != nil { + t.Error(err) + } else if replyAcc.Balances["BALANCE_TEST"].Units.Compare(utils.NewDecimal(3, 0)) != 0 { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.NewDecimal(3, 0), replyAcc.Balances["BALANCE_TEST"].Units) + } +} diff --git a/data/conf/samples/apis_actions_mysql/cgrates.json b/data/conf/samples/apis_actions_mysql/cgrates.json index b10b6261a..50a0cdbf6 100644 --- a/data/conf/samples/apis_actions_mysql/cgrates.json +++ b/data/conf/samples/apis_actions_mysql/cgrates.json @@ -1,14 +1,12 @@ { - // CGRateS Configuration file - // will be used in apis/actions_it_test.go "general": { - "log_level": 7, + "log_level": 7 }, - "data_db": { // database used to store runtime data (eg: accounts, cdr stats) - "db_type": "redis", // data_db type: - "db_port": 6379, // data_db port to reach the database - "db_name": "10", // data_db database name to connect to + "data_db": { + "db_type": "redis", + "db_port": 6379, + "db_name": "10" }, @@ -16,21 +14,26 @@ "enabled": true, "thresholds_conns": ["*internal"], "stats_conns": ["*internal"], + "accounts_conns": ["*internal"] + }, + + "accounts": { + "enabled": true }, "stats": { "enabled": true, "store_interval": "-1", - "thresholds_conns": ["*internal"], + "thresholds_conns": ["*internal"] }, "thresholds": { "enabled": true, "store_interval": "-1", - "actions_conns": ["*internal"], + "actions_conns": ["*internal"] }, "admins": { - "enabled": true, + "enabled": true } } \ No newline at end of file