diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go
index 57020ff80..9a1cdadf5 100644
--- a/accounts/abstractbalance_test.go
+++ b/accounts/abstractbalance_test.go
@@ -22,6 +22,7 @@ import (
"testing"
"time"
+ "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/ericlagergren/decimal"
@@ -533,3 +534,167 @@ func TestABCost0WithLimitExceedWithConcrete(t *testing.T) {
t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units)
}
}
+
+func TestDebitUsageFiltersError(t *testing.T) {
+ cfg := config.NewDefaultCGRConfig()
+ filters := engine.NewFilterS(cfg, nil, nil)
+ aB := &abstractBalance{
+ blnCfg: &utils.Balance{
+ ID: "ID_TEST",
+ Type: utils.MetaAbstract,
+ FilterIDs: []string{"*string:*~req.Usage:10s"},
+ CostIncrements: []*utils.CostIncrement{
+ {
+ Increment: utils.NewDecimal(int64(1*time.Second), 0),
+ RecurrentFee: utils.NewDecimal(2, 0),
+ },
+ },
+ Units: utils.NewDecimal(int64(50*time.Second), 0),
+ },
+ fltrS: filters,
+ }
+
+ cgrEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]interface{}{
+ utils.Usage: "10s",
+ },
+ }
+ _, err := aB.debitUsage(utils.NewDecimal(int64(40*time.Second), 0),
+ cgrEv)
+ if err == nil || err != utils.ErrFilterNotPassingNoCaps {
+ t.Errorf("Expected %+v, received %+v", utils.ErrFilterNotPassingNoCaps, err)
+ }
+
+ aB.blnCfg.FilterIDs = []string{"invalid_filter_format"}
+ _, err = aB.debitUsage(utils.NewDecimal(int64(40*time.Second), 0),
+ cgrEv)
+ if err == nil || err != utils.ErrNoDatabaseConn {
+ t.Errorf("Expected %+v, received %+v", utils.ErrNoDatabaseConn, err)
+ }
+}
+
+func TestDebitUsageBalanceLimitErrors(t *testing.T) {
+ aB := &abstractBalance{
+ blnCfg: &utils.Balance{
+ ID: "ID_TEST",
+ Type: utils.MetaAbstract,
+ Opts: map[string]interface{}{
+ utils.MetaBalanceLimit: "not_FLOAT64",
+ },
+ CostIncrements: []*utils.CostIncrement{
+ {
+ Increment: utils.NewDecimal(int64(1*time.Second), 0),
+ RecurrentFee: utils.NewDecimal(2, 0),
+ },
+ },
+ Units: utils.NewDecimal(int64(60*time.Second), 0),
+ },
+ fltrS: new(engine.FilterS),
+ }
+
+ cgrEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]interface{}{
+ utils.Usage: "10s",
+ },
+ }
+
+ expectedErr := "unsupported *balanceLimit format"
+ _, err := aB.debitUsage(utils.NewDecimal(int64(40*time.Second), 0),
+ cgrEv)
+ if err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+
+ aB.blnCfg.Opts[utils.MetaBalanceLimit] = float64(16 * time.Second)
+ if _, err = aB.debitUsage(utils.NewDecimal(int64(40*time.Second), 0),
+ cgrEv); err != nil {
+ t.Error(err)
+ }
+ if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(60*time.Second), 0)) != 0 {
+ t.Errorf("Expected %+v, received %+v", aB.blnCfg.Units.Big, utils.NewDecimal(int64(50*time.Second), 0))
+ }
+}
+
+func TestDebitUsageUnitFactorsErrors(t *testing.T) {
+ cfg := config.NewDefaultCGRConfig()
+ filters := engine.NewFilterS(cfg, nil, nil)
+ aB := &abstractBalance{
+ blnCfg: &utils.Balance{
+ ID: "ID_TEST",
+ Type: utils.MetaAbstract,
+ UnitFactors: []*utils.UnitFactor{
+ {
+ FilterIDs: []string{"invalid_filter_fromat"},
+ Factor: utils.NewDecimal(2, 0),
+ },
+ },
+ CostIncrements: []*utils.CostIncrement{
+ {
+ Increment: utils.NewDecimal(int64(1*time.Second), 0),
+ RecurrentFee: utils.NewDecimal(2, 0),
+ },
+ },
+ Units: utils.NewDecimal(int64(60*time.Second), 0),
+ },
+ fltrS: filters,
+ }
+
+ cgrEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]interface{}{
+ utils.Usage: "10s",
+ },
+ }
+
+ if _, err := aB.debitUsage(utils.NewDecimal(int64(20*time.Second), 0), cgrEv); err == nil || err != utils.ErrNoDatabaseConn {
+ t.Errorf("Expected %+v, received %+v", utils.ErrNoDatabaseConn, err)
+ }
+
+ aB.blnCfg.UnitFactors[0].FilterIDs = []string{"*string:*~req.Usage:10s"}
+ if ec, err := aB.debitUsage(utils.NewDecimal(int64(20*time.Second), 0), cgrEv); err != nil {
+ t.Error(err)
+ } else if ec.Usage.Cmp(decimal.New(0, 0)) != 0 {
+ t.Error(err)
+ }
+}
+
+func TestDebitUsageCostIncrementError(t *testing.T) {
+ cfg := config.NewDefaultCGRConfig()
+ filters := engine.NewFilterS(cfg, nil, nil)
+ aB := &abstractBalance{
+ blnCfg: &utils.Balance{
+ ID: "ID_TEST",
+ Type: utils.MetaAbstract,
+ CostIncrements: []*utils.CostIncrement{
+ {
+ FilterIDs: []string{"INVALID_FILTER_FORMAT"},
+ Increment: utils.NewDecimal(int64(1*time.Second), 0),
+ RecurrentFee: utils.NewDecimal(2, 0),
+ },
+ },
+ Units: utils.NewDecimal(int64(60*time.Second), 0),
+ },
+ fltrS: filters,
+ }
+ cgrEv := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]interface{}{
+ utils.Usage: "10s",
+ },
+ }
+
+ if _, err := aB.debitUsage(utils.NewDecimal(int64(20*time.Second), 0), cgrEv); err == nil || err != utils.ErrNoDatabaseConn {
+ t.Errorf("Expected %+v, received %+v", utils.ErrNoDatabaseConn, err)
+ }
+
+ //Will check the error by making the event charge
+ //the cost is unknown, will use attributes to query from rates
+ aB.blnCfg.CostIncrements = nil
+ aB.blnCfg.AttributeIDs = []string{"attr11"}
+ expected := "NOT_CONNECTED: AttributeS"
+ if _, err := aB.debitUsage(utils.NewDecimal(int64(20*time.Second), 0), cgrEv); err == nil || err.Error() != expected {
+ t.Errorf("Expected %+v, received %+v", expected, err)
+ }
+}
diff --git a/accounts/libaccounts_test.go b/accounts/libaccounts_test.go
new file mode 100644
index 000000000..85acb82db
--- /dev/null
+++ b/accounts/libaccounts_test.go
@@ -0,0 +1,130 @@
+/*
+Real-time Online/Offline Charging System (OerS) 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 accounts
+
+import (
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/cgrates/cgrates/config"
+
+ "github.com/cgrates/rpcclient"
+
+ "github.com/cgrates/cgrates/engine"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+func TestNewAccountBalanceOperators(t *testing.T) {
+ acntPrf := &utils.AccountProfile{
+ ID: "TEST_ID",
+ Tenant: "cgrates.org",
+ Balances: map[string]*utils.Balance{
+ "BL0": {
+ ID: "BALANCE1",
+ Type: utils.MetaAbstract,
+ },
+ "BL1": {
+ ID: "BALANCE1",
+ Type: utils.MetaConcrete,
+ CostIncrements: []*utils.CostIncrement{
+ {
+ Increment: utils.NewDecimal(int64(time.Second), 0),
+ },
+ },
+ },
+ },
+ }
+ config := config.NewDefaultCGRConfig()
+ filters := engine.NewFilterS(config, nil, nil)
+
+ concrete, err := newBalanceOperator(acntPrf.Balances["BL1"], nil, filters, nil, nil, nil)
+ if err != nil {
+ t.Error(err)
+ }
+ var cncrtBlncs []*concreteBalance
+ cncrtBlncs = append(cncrtBlncs, concrete.(*concreteBalance))
+
+ expected := &abstractBalance{
+ blnCfg: acntPrf.Balances["BL0"],
+ fltrS: filters,
+ cncrtBlncs: cncrtBlncs,
+ }
+
+ if blcOp, err := newAccountBalanceOperators(acntPrf, filters, nil,
+ nil, nil); err != nil {
+ t.Error(err)
+ } else {
+ rcv := blcOp[0].(*abstractBalance)
+ if !reflect.DeepEqual(expected, rcv) {
+ t.Errorf("Expected %+v, received %+v", expected, rcv)
+ }
+ }
+
+ acntPrf.Balances["BL1"].Type = "INVALID_TYPE"
+ expectedErr := "unsupported balance type: "
+ if _, err := newAccountBalanceOperators(acntPrf, filters, nil,
+ nil, nil); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+}
+
+type testMockCall struct {
+ calls map[string]func(args interface{}, reply interface{}) error
+}
+
+func (tS *testMockCall) Call(method string, args interface{}, rply interface{}) error {
+ if call, has := tS.calls[method]; !has {
+ return rpcclient.ErrUnsupporteServiceMethod
+ } else {
+ return call(args, rply)
+ }
+}
+
+func TestProcessAttributeS(t *testing.T) {
+ engine.Cache.Clear(nil)
+
+ config := config.NewDefaultCGRConfig()
+ sTestMock := &testMockCall{
+ calls: map[string]func(args interface{}, reply interface{}) error{
+ utils.AttributeSv1ProcessEvent: func(args interface{}, reply interface{}) error {
+ return utils.ErrNotImplemented
+ },
+ },
+ }
+ chanInternal := make(chan rpcclient.ClientConnector, 1)
+ chanInternal <- sTestMock
+ connMgr := engine.NewConnManager(config, map[string]chan rpcclient.ClientConnector{
+ utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
+ })
+ cgrEvent := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "TEST_ID1",
+ Opts: map[string]interface{}{
+ utils.OptsAttributesProcessRuns: "20",
+ },
+ }
+
+ attrsConns := []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
+
+ if _, err := processAttributeS(connMgr, cgrEvent, attrsConns, nil); err == nil || err != utils.ErrNotImplemented {
+ t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
+ }
+}