Files
cgrates/apis/accounts_it_test.go
ionutboangiu 0653e9b5d7 Apply go fmt
2022-08-24 09:32:23 +03:00

1962 lines
49 KiB
Go

//go:build integration
// +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 <http://www.gnu.org/licenses/>
*/
package apis
import (
"path"
"reflect"
"sort"
"testing"
"time"
"github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
var (
accPrfCfgPath string
accPrfCfg *config.CGRConfig
accSRPC *birpc.Client
accPrfConfigDIR string //run tests for specific configuration
sTestsAccPrf = []func(t *testing.T){
testAccSInitCfg,
testAccSInitDataDb,
testAccSStartEngine,
testAccSRPCConn,
testGetAccProfileBeforeSet,
testGetAccProfilesBeforeSet,
testAccSetAccProfile,
testAccGetAccIDs,
testAccGetAccs,
testAccGetAccIDsCount,
testGetAccBeforeSet2,
testAccSetAcc2,
testAccGetAccIDs2,
testAccGetAccs2,
testAccGetAccIDsCount2,
testAccRemoveAcc,
testAccGetAccs3,
testAccGetAccsWithPrefix,
testAccGetAccountsForEvent,
testAccMaxAbstracts,
testAccDebitAbstracts,
testAccMaxConcretes,
testAccDebitConcretes,
// RefundCharges test
testAccRefundCharges,
testAccActionSetRmvBalance,
// Account with blocker debit
testAccSInitDataDb,
testAccSCacheClear,
testAccDebitAbstractWithoutBlockers,
testAccDebitAbstractWithBlockers,
testAccDebitAbstractWithBlockersOnBalance,
testAccSKillEngine,
}
)
func TestAccSIT(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
accPrfConfigDIR = "tutinternal"
case utils.MetaMongo:
accPrfConfigDIR = "tutmongo"
case utils.MetaMySQL:
accPrfConfigDIR = "tutmysql"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
for _, stest := range sTestsAccPrf {
t.Run(accPrfConfigDIR, stest)
}
}
func testAccSInitCfg(t *testing.T) {
var err error
accPrfCfgPath = path.Join(*dataDir, "conf", "samples", accPrfConfigDIR)
accPrfCfg, err = config.NewCGRConfigFromPath(context.Background(), accPrfCfgPath)
if err != nil {
t.Error(err)
}
}
func testAccSInitDataDb(t *testing.T) {
if err := engine.InitDataDB(accPrfCfg); err != nil {
t.Fatal(err)
}
}
// Start CGR Engine
func testAccSStartEngine(t *testing.T) {
if _, err := engine.StopStartEngine(accPrfCfgPath, *waitRater); err != nil {
t.Fatal(err)
}
}
func testAccSRPCConn(t *testing.T) {
var err error
accSRPC, err = newRPCClient(accPrfCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
if err != nil {
t.Fatal(err)
}
}
func testGetAccProfileBeforeSet(t *testing.T) {
var reply *utils.TenantIDWithAPIOpts
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: utils.CGRateSorg,
ID: "TEST_ACC_IT_TEST",
},
}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Error(err)
}
}
func testGetAccProfilesBeforeSet(t *testing.T) {
var reply *[]*utils.Account
args := &utils.ArgsItemIDs{}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccounts,
args, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Error(err)
}
}
func testAccSetAccProfile(t *testing.T) {
args := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
},
APIOpts: nil,
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
args, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
expectedAcc := utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
}
var result utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "",
ID: "TEST_ACC_IT_TEST",
},
}, &result); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(result, expectedAcc) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expectedAcc), utils.ToJSON(result))
}
}
func testAccGetAccIDs(t *testing.T) {
var reply []string
args := &utils.ArgsItemIDs{
Tenant: "cgrates.org",
}
expected := []string{"TEST_ACC_IT_TEST"}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccountIDs,
args, &reply); err != nil {
t.Error(err)
} else if len(reply) != len(expected) {
t.Errorf("Expected %+v \n, received %+v", expected, reply)
}
}
func testAccGetAccs(t *testing.T) {
var reply *[]*utils.Account
args := &utils.ArgsItemIDs{}
expected := &[](*utils.Account){
{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccounts,
args, &reply); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply, expected) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expected), utils.ToJSON(reply))
}
}
func testAccGetAccIDsCount(t *testing.T) {
var reply int
args := &utils.ArgsItemIDs{
Tenant: utils.CGRateSorg,
ItemsPrefix: "",
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccountsCount,
args, &reply); err != nil {
t.Error(err)
} else if reply != 1 {
t.Errorf("Expected %+v \n, received %+v", 1, reply)
}
}
func testGetAccBeforeSet2(t *testing.T) {
var reply *utils.TenantIDWithAPIOpts
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: utils.CGRateSorg,
ID: "TEST_ACC_IT_TEST_SECOND",
},
}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Error(err)
}
}
func testAccSetAcc2(t *testing.T) {
args := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
},
APIOpts: nil,
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
args, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
expectedAcc := utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
}
var result utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "",
ID: "TEST_ACC_IT_TEST2",
},
}, &result); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(result, expectedAcc) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expectedAcc), utils.ToJSON(result))
}
}
func testAccGetAccIDs2(t *testing.T) {
var reply []string
args := &utils.ArgsItemIDs{
Tenant: "cgrates.org",
}
expected := []string{"TEST_ACC_IT_TEST", "TEST_ACC_IT_TEST2"}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccountIDs,
args, &reply); err != nil {
t.Error(err)
} else if len(reply) != len(expected) {
t.Errorf("Expected %+v \n, received %+v", expected, reply)
}
}
func testAccGetAccs2(t *testing.T) {
var reply *[]*utils.Account
args := &utils.ArgsItemIDs{}
expected := &[](*utils.Account){
{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccounts,
args, &reply); err != nil {
t.Error(err)
}
sort.Slice(*reply, func(i, j int) bool {
return (*reply)[i].ID < (*reply)[j].ID
})
if !reflect.DeepEqual(reply, expected) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expected), utils.ToJSON(reply))
}
}
func testAccGetAccIDsCount2(t *testing.T) {
var reply int
args := &utils.ArgsItemIDs{
Tenant: utils.CGRateSorg,
ItemsPrefix: "",
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccountsCount,
args, &reply); err != nil {
t.Error(err)
} else if reply != 2 {
t.Errorf("Expected %+v \n, received %+v", 2, reply)
}
}
func testAccRemoveAcc(t *testing.T) {
var reply string
args := &utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
ID: "TEST_ACC_IT_TEST2",
Tenant: utils.CGRateSorg,
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1RemoveAccount,
args, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected %+v \n, received %+v", utils.OK, reply)
}
//nothing to get from db
var result *utils.RateProfile
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: utils.CGRateSorg,
ID: "TEST_ACC_IT_TEST2",
},
}, &result); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Expected %+v \n, received %+v", utils.ErrNotFound, err)
}
}
func testAccGetAccs3(t *testing.T) {
var reply *[]*utils.Account
args := &utils.ArgsItemIDs{}
expected := &[](*utils.Account){
{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccounts,
args, &reply); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply, expected) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expected), utils.ToJSON(reply))
}
}
func testAccGetAccsWithPrefix(t *testing.T) {
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "aTEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
},
APIOpts: nil,
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
expectedAcc := utils.Account{
Tenant: "cgrates.org",
ID: "aTEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
}
var result utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "",
ID: "aTEST_ACC_IT_TEST2",
},
}, &result); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(result, expectedAcc) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expectedAcc), utils.ToJSON(result))
}
var reply2 *[]*utils.Account
args := &utils.ArgsItemIDs{
ItemsPrefix: "aTEST",
}
expected := &[]*utils.Account{
{
Tenant: "cgrates.org",
ID: "aTEST_ACC_IT_TEST2",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccounts,
args, &reply2); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply2, expected) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expected), utils.ToJSON(reply2))
}
}
func testAccGetAccountsForEvent(t *testing.T) {
var reply []*utils.Account
expected := []*utils.Account{
{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
},
}
ev := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
utils.Usage: 20 * time.Second,
},
APIOpts: map[string]interface{}{
utils.OptsAccountsProfileIDs: "TEST_ACC_IT_TEST",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1AccountsForEvent,
ev, &reply); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply, expected) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(reply))
}
}
func testAccMaxAbstracts(t *testing.T) {
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST4",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(213, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
},
},
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
var reply3 *utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
utils.AccountField: "1004",
},
APIOpts: map[string]interface{}{
utils.MetaUsage: "27s",
utils.OptsAccountsProfileIDs: "TEST_ACC_IT_TEST4",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1MaxAbstracts,
ev2, &reply3); err != nil {
t.Error(err)
}
expected2 := &utils.EventCharges{
Abstracts: utils.NewDecimal(int64(27*time.Second), 0),
Charges: []*utils.ChargeEntry{
{
ChargingID: "charge1",
CompressFactor: 1,
},
},
Accounting: map[string]*utils.AccountCharge{
"charge1": {
AccountID: "TEST_ACC_IT_TEST4",
BalanceID: "AbstractBalance1",
Units: utils.NewDecimal(int64(27*time.Second), 0),
BalanceLimit: utils.NewDecimal(0, 0),
RatingID: "Rating1",
},
},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{
"Rating1": {
Increments: []*utils.RateSIncrement{
{
RateIntervalIndex: 0,
RateID: "rate1",
CompressFactor: 1,
}},
CompressFactor: 1,
}},
Rates: map[string]*utils.IntervalRate{
"rate1": {
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Accounts: map[string]*utils.Account{
"TEST_ACC_IT_TEST4": {
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST4",
FilterIDs: []string{"*string:~*req.Account:1004"},
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: "*abstract",
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Units: utils.NewDecimal(int64(13*time.Second), 0),
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
FilterIDs: nil,
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: "*concrete",
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Units: utils.NewDecimal(213, 0),
},
},
},
},
}
if !reply3.Equals(expected2) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected2), utils.ToJSON(reply3))
}
}
func testAccDebitAbstracts(t *testing.T) {
args := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST5",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(213, 0),
},
},
},
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
args, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
var reply3 utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
utils.AccountField: "1004",
},
APIOpts: map[string]interface{}{
utils.MetaUsage: "27s",
utils.OptsAccountsProfileIDs: "TEST_ACC_IT_TEST5",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1DebitAbstracts,
ev2, &reply3); err != nil {
t.Error(err)
}
expected2 := utils.EventCharges{
Abstracts: utils.NewDecimal(int64(27*time.Second), 0),
Charges: []*utils.ChargeEntry{
{
ChargingID: "charge1",
CompressFactor: 1,
},
},
Accounting: map[string]*utils.AccountCharge{
"charge1": &utils.AccountCharge{
AccountID: "TEST_ACC_IT_TEST5",
BalanceID: "AbstractBalance1",
Units: utils.NewDecimal(int64(27*time.Second), 0),
BalanceLimit: utils.NewDecimal(0, 0),
RatingID: "rating1",
JoinedChargeIDs: nil,
},
},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{
"rating1": {
Increments: []*utils.RateSIncrement{{
RateIntervalIndex: 0,
RateID: "rate1",
CompressFactor: 1,
}},
CompressFactor: 1,
},
},
Rates: map[string]*utils.IntervalRate{
"rate1": {
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Accounts: map[string]*utils.Account{
"TEST_ACC_IT_TEST5": {
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST5",
FilterIDs: []string{"*string:~*req.Account:1004"},
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: "*abstract",
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Units: utils.NewDecimal(int64(13*time.Second), 0),
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
FilterIDs: nil,
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: "*concrete",
Units: utils.NewDecimal(213, 0),
},
},
},
},
}
if !expected2.Equals(&reply3) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected2), utils.ToJSON(reply3))
}
}
func testAccMaxConcretes(t *testing.T) {
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST6",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(213, 0),
},
},
},
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
var reply3 utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
utils.AccountField: "1004",
},
APIOpts: map[string]interface{}{
utils.OptsRatesIntervalStart: "27s",
utils.OptsAccountsProfileIDs: "TEST_ACC_IT_TEST6",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1MaxConcretes,
ev2, &reply3); err != nil {
t.Error(err)
}
var crgID string
for _, val := range reply3.Charges {
crgID = val.ChargingID
}
var accKEy, rtID string
for key, val := range reply3.Accounting {
accKEy = key
rtID = val.RatingID
}
expRating := &utils.RateSInterval{
IntervalStart: nil,
Increments: []*utils.RateSIncrement{
{
RateIntervalIndex: 0,
RateID: utils.EmptyString,
CompressFactor: 0,
},
},
CompressFactor: 1,
}
for _, val := range reply3.Rating {
if !reflect.DeepEqual(val, expRating) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expRating, val)
}
}
reply3.Rating = map[string]*utils.RateSInterval{}
expected2 := utils.EventCharges{
Concretes: utils.NewDecimal(213, 0),
Charges: []*utils.ChargeEntry{
{
ChargingID: crgID,
CompressFactor: 1,
},
},
Accounting: map[string]*utils.AccountCharge{
accKEy: &utils.AccountCharge{
AccountID: "TEST_ACC_IT_TEST6",
BalanceID: "ConcreteBalance2",
Units: utils.NewDecimal(213, 0),
BalanceLimit: utils.NewDecimal(0, 0),
RatingID: rtID,
},
},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"TEST_ACC_IT_TEST6": {
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST6",
FilterIDs: []string{"*string:~*req.Account:1004"},
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: "*abstract",
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Units: utils.NewDecimal(int64(40*time.Second), 0),
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: "*concrete",
Units: utils.NewDecimal(0, 0),
},
},
},
},
}
if !reflect.DeepEqual(reply3, expected2) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected2), utils.ToJSON(reply3))
}
}
func testAccDebitConcretes(t *testing.T) {
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST7",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
FilterIDs: []string{"*string:~*req.Account:1004"},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(40*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(213, 0),
},
},
},
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
var reply3 utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
utils.AccountField: "1004",
},
APIOpts: map[string]interface{}{
utils.OptsAccountsUsage: "27s",
utils.OptsAccountsProfileIDs: "TEST_ACC_IT_TEST7",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1DebitConcretes,
ev2, &reply3); err != nil {
t.Error(err)
}
var crgID string
for _, val := range reply3.Charges {
crgID = val.ChargingID
}
var accKEy, rtID string
for key, val := range reply3.Accounting {
accKEy = key
rtID = val.RatingID
}
expRating := &utils.RateSInterval{
Increments: []*utils.RateSIncrement{
{
RateIntervalIndex: 0,
CompressFactor: 0,
},
},
CompressFactor: 1,
}
for _, val := range reply3.Rating {
if !reflect.DeepEqual(val, expRating) {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expRating, val)
}
}
reply3.Rating = map[string]*utils.RateSInterval{}
expected2 := utils.EventCharges{
Concretes: utils.NewDecimal(213, 0),
Charges: []*utils.ChargeEntry{
{
ChargingID: crgID,
CompressFactor: 1,
},
},
Accounting: map[string]*utils.AccountCharge{
accKEy: &utils.AccountCharge{
AccountID: "TEST_ACC_IT_TEST7",
BalanceID: "ConcreteBalance2",
Units: utils.NewDecimal(213, 0),
BalanceLimit: utils.NewDecimal(0, 0),
RatingID: rtID,
},
},
UnitFactors: map[string]*utils.UnitFactor{},
Rating: map[string]*utils.RateSInterval{},
Rates: map[string]*utils.IntervalRate{},
Accounts: map[string]*utils.Account{
"TEST_ACC_IT_TEST7": {
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST7",
FilterIDs: []string{"*string:~*req.Account:1004"},
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
Balances: map[string]*utils.Balance{
"AbstractBalance1": {
ID: "AbstractBalance1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: "*abstract",
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(0, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
Units: utils.NewDecimal(int64(40*time.Second), 0),
},
"ConcreteBalance2": {
ID: "ConcreteBalance2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: "*concrete",
Units: utils.NewDecimal(0, 0),
},
},
},
},
}
if !reflect.DeepEqual(reply3, expected2) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected2), utils.ToJSON(reply3))
}
}
func testAccRefundCharges(t *testing.T) {
// we will set an account, we will debit it (with debitAbtracts), and after that we will call refundCharges to get back our units from the cost
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "AccountRefundCharges",
Weights: utils.DynamicWeights{
{
Weight: 0,
},
},
FilterIDs: []string{"*exists:~*opts.*acntUsage:", "*string:~*req.Destination:1004"},
Balances: map[string]*utils.Balance{
"AB": {
ID: "AB",
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(5*time.Minute), 0), // 300s
UnitFactors: []*utils.UnitFactor{
{
Factor: utils.NewDecimal(10, 0),
},
},
Opts: map[string]interface{}{
utils.MetaBalanceLimit: -100.0,
},
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(6, 1),
RecurrentFee: utils.NewDecimal(1, 1),
},
},
},
"CB": {
ID: "CB",
Weights: utils.DynamicWeights{
{
Weight: 5,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(500, 1),
UnitFactors: []*utils.UnitFactor{
{
Factor: utils.NewDecimal(15, 0),
},
},
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
RecurrentFee: utils.NewDecimal(1, 1),
},
},
},
},
},
}
var replyStr string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &replyStr); err != nil {
t.Error(err)
} else if replyStr != utils.OK {
t.Error(err)
}
var reply utils.EventCharges
ev := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "tesRefundCHarges",
Event: map[string]interface{}{
utils.AccountField: "1001",
utils.Destination: "1004",
},
APIOpts: map[string]interface{}{
utils.OptsAccountsUsage: "3m27s",
utils.OptsAccountsProfileIDs: "AccountRefundCharges",
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1DebitAbstracts,
ev, &reply); err != nil {
t.Error(err)
}
// we will compare the costs of the eventCharges and the abstracts/concretes
concreteCost := utils.NewDecimal(33, 1) // 3.3 were debited of concretes (3.3 intially and because of 15 unit factor of CB --> 3.3 * 15 = 49.5 units were taken from CB)
abstractCost := utils.NewDecimal(int64(27*time.Second), 0) // 27s were debited of abstracts,
if !reflect.DeepEqual(abstractCost, reply.Abstracts) {
t.Errorf("Expected %v, received %v", abstractCost, reply.Abstracts)
}
if !reflect.DeepEqual(concreteCost, reply.Concretes) {
t.Errorf("Expected %v, received %v", abstractCost, reply.Charges)
}
// 50 - 49.5(3.3 * 15 uf) = 0.5 3m27s --> 207 seconds --> 2.7 debit + 0.6 fixedFee = 3.3 debited
// we will get the Account after the debit was made
var result *utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "cgrates.org",
ID: "AccountRefundCharges",
},
}, &result); err != nil {
t.Error(err)
} else {
//now we will compare the units from both balances to see that the debit took the untis from account
astractUnitsRemain := utils.NewDecimal(int64(30*time.Second), 0) // 5m - 27s because of uf --> 300s - 270s(27 * 10uf) = 30s
if !reflect.DeepEqual(result.Balances["AB"].Units, astractUnitsRemain) {
t.Errorf("Expected %v, received %v", astractUnitsRemain, result.Balances["AB"].Units)
}
concretesUnitsRemain := utils.NewDecimal(5, 1) // 50 - 49.5
if !reflect.DeepEqual(result.Balances["CB"].Units, concretesUnitsRemain) {
t.Errorf("Expected %v, received %v", concretesUnitsRemain, result.Balances["CB"].Units)
}
}
// now as the account was debited, we will refund those charges
args := &utils.APIEventCharges{
Tenant: "cgrates.org",
EventCharges: &reply, // this reply was the eventCharges from the previous debit
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1RefundCharges,
args, &replyStr); err != nil {
t.Error(err)
} else if replyStr != utils.OK {
t.Error(err)
}
// now that the refund was called properly, we will check the account to see the changes
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "cgrates.org",
ID: "AccountRefundCharges",
},
}, &result); err != nil {
t.Error(err)
} else {
if !reflect.DeepEqual(result, acc.Account) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(acc.Account), utils.ToJSON(result))
}
}
}
func testAccActionSetRmvBalance(t *testing.T) {
acc := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST8",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
},
APIOpts: nil,
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
var reply3 string
args2 := &utils.ArgsActSetBalance{
AccountID: "TEST_ACC_IT_TEST8",
Tenant: "cgrates.org",
Diktats: []*utils.BalDiktat{
{
Path: "*balance.AbstractBalance3.Units",
Value: "10",
},
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1ActionSetBalance,
args2, &reply3); err != nil {
t.Error(err)
} else if reply3 != utils.OK {
t.Errorf("Expected %+v \n, received %+v", utils.OK, utils.OK)
}
expectedAcc := utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST8",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"AbstractBalance3": {
ID: "AbstractBalance3",
Type: "*concrete",
Units: utils.NewDecimal(10, 0),
CostIncrements: []*utils.CostIncrement{
{
FilterIDs: []string{"*string:~*req.ToR:*voice"},
Increment: utils.NewDecimal(1000000000, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
{
FilterIDs: []string{"*string:~*req.ToR:*data"},
Increment: utils.NewDecimal(1048576, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
{
FilterIDs: []string{"*string:~*req.ToR:*sms"},
Increment: utils.NewDecimal(1, 0),
RecurrentFee: utils.NewDecimal(0, 0),
},
},
},
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
}
var result utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "",
ID: "TEST_ACC_IT_TEST8",
},
}, &result); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(result, expectedAcc) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expectedAcc), utils.ToJSON(result))
}
var reply4 string
args3 := &utils.ArgsActRemoveBalances{
Tenant: "",
AccountID: "TEST_ACC_IT_TEST8",
BalanceIDs: []string{"AbstractBalance3"},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1ActionRemoveBalance,
args3, &reply4); err != nil {
t.Error(err)
}
if !reflect.DeepEqual(reply4, `OK`) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(`OK`), utils.ToJSON(reply4))
}
expectedAcc2 := utils.Account{
Tenant: "cgrates.org",
ID: "TEST_ACC_IT_TEST8",
Opts: map[string]interface{}{},
Balances: map[string]*utils.Balance{
"VoiceBalance": {
ID: "VoiceBalance",
FilterIDs: []string{"*string:~*req.Account:1001"},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 12,
},
},
Type: "*abstract",
Opts: map[string]interface{}{
"Destination": "10",
},
Units: utils.NewDecimal(0, 0),
},
},
Weights: utils.DynamicWeights{
{
FilterIDs: nil,
Weight: 10,
},
},
}
var result2 utils.Account
if err := accSRPC.Call(context.Background(), utils.AdminSv1GetAccount,
&utils.TenantIDWithAPIOpts{
TenantID: &utils.TenantID{
Tenant: "",
ID: "TEST_ACC_IT_TEST8",
},
}, &result2); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(result2, expectedAcc2) {
t.Errorf("\nExpected %+v , \nreceived %+v", utils.ToJSON(expectedAcc2), utils.ToJSON(result2))
}
}
func testAccSCacheClear(t *testing.T) {
var reply string
if err := accSRPC.Call(context.Background(), utils.CacheSv1Clear,
&utils.AttrCacheIDsWithAPIOpts{
CacheIDs: nil,
}, &reply); err != nil {
t.Error(err)
}
}
func testAccDebitAbstractWithoutBlockers(t *testing.T) {
acc1 := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "AccountBlocker1",
Weights: utils.DynamicWeights{
{
Weight: 10,
},
},
FilterIDs: []string{"*string:~*req.Blockers:*exists"},
Blockers: utils.DynamicBlockers{
{
Blocker: false,
},
},
Balances: map[string]*utils.Balance{
"AB1": {
ID: "AB1",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(70*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
FixedFee: utils.NewDecimal(6, 1),
RecurrentFee: utils.NewDecimal(int64(time.Second), 0),
},
},
},
"CB1": {
ID: "CB1",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
UnitFactors: []*utils.UnitFactor{
{
Factor: utils.NewDecimal(10, 0),
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(999, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(2, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
},
}
var reply string
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc1, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
acc2 := &utils.AccountWithAPIOpts{
Account: &utils.Account{
Tenant: "cgrates.org",
ID: "AccountBlocker2",
Weights: utils.DynamicWeights{
{
Weight: 15,
},
},
Blockers: utils.DynamicBlockers{
{
FilterIDs: []string{"*string:~*req.Destination:1002"},
Blocker: true,
},
},
FilterIDs: []string{"*string:~*req.Blockers:*exists"},
Balances: map[string]*utils.Balance{
"AB_ForBlocker": {
ID: "AB_ForBLocker",
Weights: utils.DynamicWeights{
{
Weight: 30,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(5*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(3*time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(time.Second), 0),
},
},
},
"CB_WIthBlocker": {
ID: "CB_WIthBlocker",
Weights: utils.DynamicWeights{
{
Weight: 28,
},
},
Blockers: utils.DynamicBlockers{
{
FilterIDs: []string{"*string:~*req.BlockerAbstract:yes"},
Blocker: true,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(5, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(1, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
"AB2": {
ID: "AB2",
Weights: utils.DynamicWeights{
{
Weight: 25,
},
},
Type: utils.MetaAbstract,
Units: utils.NewDecimal(int64(20*time.Second), 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(int64(time.Second), 0),
RecurrentFee: utils.NewDecimal(int64(time.Second), 0),
},
},
},
"CB2": {
ID: "CB2",
Weights: utils.DynamicWeights{
{
Weight: 20,
},
},
Type: utils.MetaConcrete,
Units: utils.NewDecimal(100, 0),
CostIncrements: []*utils.CostIncrement{
{
Increment: utils.NewDecimal(1, 0),
RecurrentFee: utils.NewDecimal(1, 0),
},
},
},
},
},
}
if err := accSRPC.Call(context.Background(), utils.AdminSv1SetAccount,
acc2, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Error(err)
}
// We will try to use de maxAbstratct to see the cost for from both accounts matched, without blocker for now. In order to match blocker, Destination must be 1002
var replyEv *utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
"Blockers": "*exists",
utils.AccountField: "101223",
utils.Destination: "1002",
},
APIOpts: map[string]interface{}{
utils.MetaUsage: 90 * time.Second,
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1MaxAbstracts,
ev2, &replyEv); err != nil {
t.Error(err)
} else {
// AccountBlocker1 should not be debited!!!
if _, has := replyEv.Accounts["AccountBlocker1"]; has {
t.Errorf("The accounts %v was not debited", "AccountBlocker1")
}
if _, has := replyEv.Accounts["AccountBlocker2"]; !has {
t.Errorf("The accounts %v was not debited", "AccountBlocker2")
}
}
}
func testAccDebitAbstractWithBlockers(t *testing.T) {
// we will try to use de maxAbstratct to see the cost for from one account matched, with blocker for now (it will be AccountBlocker2)
var replyEv *utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
"Blockers": "*exists",
utils.AccountField: "101223",
},
APIOpts: map[string]interface{}{
utils.MetaUsage: 90 * time.Second,
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1MaxAbstracts,
ev2, &replyEv); err != nil {
t.Error(err)
} else {
// the debit worked properly, it was debited from both accounts, but the next accoutns from the balance named "CB_WIthBlocker" should not be debited
if _, has := replyEv.Accounts["AccountBlocker1"]; !has {
t.Errorf("The accounts %v was not debited", "AccountBlocker1")
}
if _, has := replyEv.Accounts["AccountBlocker2"]; !has {
t.Errorf("The accounts %v was not debited", "AccountBlocker2")
}
}
}
func testAccDebitAbstractWithBlockersOnBalance(t *testing.T) {
// AB_WithBLocker balance from AccountBLocker2 account will be the first balance to be charged, but it has blocker when BlockerAbstract field exist, this will stop deibting the other balances from AccountBLocker2
var replyEv *utils.EventCharges
ev2 := &utils.CGREvent{
Tenant: utils.CGRateSorg,
ID: "testIDEvent",
Event: map[string]interface{}{
"Blockers": "*exists",
utils.AccountField: "101223",
"BlockerAbstract": "yes",
},
APIOpts: map[string]interface{}{
utils.MetaUsage: 90 * time.Second,
},
}
if err := accSRPC.Call(context.Background(), utils.AccountSv1DebitAbstracts,
ev2, &replyEv); err != nil {
t.Error(err)
} else {
// the debit worked properly, it was debited from both accounts
if _, has := replyEv.Accounts["AccountBlocker1"]; !has {
t.Errorf("The accounts %v was not debited", "AccountBlocker1")
}
if _, has := replyEv.Accounts["AccountBlocker2"]; !has {
t.Errorf("The accounts %v was not debited", "AccountBlocker2")
} else {
// CB_WithBlocker balance has a blocker, so the next two balances will be skipped
for _, acc := range replyEv.Accounting {
if acc.BalanceID == "AB2" || acc.BalanceID == "CB2" {
t.Errorf("The balance <%s> from <AccountBlocker2> should not be debited", acc.BalanceID)
}
}
}
}
}
// Kill the engine when it is about to be finished
func testAccSKillEngine(t *testing.T) {
if err := engine.KillEngine(100); err != nil {
t.Error(err)
}
}