diff --git a/accounts/concretebalance_test.go b/accounts/concretebalance_test.go index 99a411e69..b82f95b99 100644 --- a/accounts/concretebalance_test.go +++ b/accounts/concretebalance_test.go @@ -22,6 +22,8 @@ import ( "reflect" "testing" + "github.com/cgrates/rpcclient" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -590,3 +592,229 @@ func TestCBDebitWithInvalidLimit(t *testing.T) { t.Error(err) } } + +func TestCBSDebitUsage(t *testing.T) { + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(1, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + toDebit := utils.NewDecimal(10, 0) + if dbted, err := cb.debitUsage(toDebit, + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if dbted.Usage.Compare(toDebit) != 0 { + t.Errorf("debited: %+v", dbted) + } else if cb.blnCfg.Units.Cmp(decimal.New(498, 0)) != 0 { + t.Errorf("balance remaining: %s", cb.blnCfg.Units) + } +} + +func TestCBSDebitUsageInvalidFilter(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + data := engine.NewInternalDB(nil, nil, true) + dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) + filterS := engine.NewFilterS(cfg, nil, dm) + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + FilterIDs: []string{"*string"}, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(1, 0), + }, + }, + }, + fltrS: filterS, + } + toDebit := utils.NewDecimal(10, 0) + if _, err := cb.debitUsage(toDebit, + new(utils.CGREvent)); err == nil || err.Error() != "inline parse error for string: <*string>" { + t.Error(err) + } +} + +func TestCBSDebitUsageNoMatchFilter(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + data := engine.NewInternalDB(nil, nil, true) + dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) + filterS := engine.NewFilterS(cfg, nil, dm) + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + FilterIDs: []string{"*string:~*req.CustomField:CustomValue"}, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(1, 0), + }, + }, + }, + fltrS: filterS, + } + cgrEv := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EV", + Event: map[string]interface{}{ + "CustomField2": "CustomValue2", + }, + } + toDebit := utils.NewDecimal(10, 0) + if _, err := cb.debitUsage(toDebit, + cgrEv); err == nil || err != utils.ErrFilterNotPassingNoCaps { + t.Error(err) + } +} + +func TestCBSDebitUsageInvalidCostIncrementFilter(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + data := engine.NewInternalDB(nil, nil, true) + dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) + filterS := engine.NewFilterS(cfg, nil, dm) + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + CostIncrements: []*utils.CostIncrement{ + { + FilterIDs: []string{"*string"}, + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(1, 0), + }, + }, + }, + fltrS: filterS, + } + toDebit := utils.NewDecimal(10, 0) + if _, err := cb.debitUsage(toDebit, + new(utils.CGREvent)); err == nil || err.Error() != "inline parse error for string: <*string>" { + t.Error(err) + } +} + +func TestCBSDebitUsageCoverProcessAttributes(t *testing.T) { // coverage purpose + cfg := config.NewDefaultCGRConfig() + data := engine.NewInternalDB(nil, nil, true) + dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) + filterS := engine.NewFilterS(cfg, nil, dm) + + engine.Cache.Clear(nil) + + 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(cfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal, + }) + + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(-1, 0), + }, + }, + AttributeIDs: []string{"CustomAttr"}, + }, + fltrS: filterS, + connMgr: connMgr, + } + toDebit := utils.NewDecimal(10, 0) + if _, err := cb.debitUsage(toDebit, + new(utils.CGREvent)); err == nil || err.Error() != "NOT_CONNECTED: AttributeS" { + t.Error(err) + } +} + +func TestCBSDebitUsageCoverProcessAttributes2(t *testing.T) { // coverage purpose + cfg := config.NewDefaultCGRConfig() + data := engine.NewInternalDB(nil, nil, true) + dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) + filterS := engine.NewFilterS(cfg, nil, dm) + + engine.Cache.Clear(nil) + + sTestMock := &testMockCall{ + calls: map[string]func(args interface{}, reply interface{}) error{ + utils.AttributeSv1ProcessEvent: func(args interface{}, reply interface{}) error { + rplCast, canCast := reply.(*engine.AttrSProcessEventReply) + if !canCast { + t.Errorf("Wrong argument type : %T", reply) + return nil + } + customEv := &engine.AttrSProcessEventReply{ + MatchedProfiles: nil, + AlteredFields: []string{"CustomField2"}, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "EV", + Event: map[string]interface{}{ + "CustomField2": "CustomValue2", + }, + }, + } + *rplCast = *customEv + return nil + }, + }, + } + chanInternal := make(chan rpcclient.ClientConnector, 1) + chanInternal <- sTestMock + connMgr := engine.NewConnManager(cfg, map[string]chan rpcclient.ClientConnector{ + utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal, + }) + + // debit 10 units from a concrete balance with 500 units + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(500, 0), // 500 Units + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(5, 0), + RecurrentFee: utils.NewDecimal(-1, 0), + }, + }, + AttributeIDs: []string{"CustomAttr"}, + }, + fltrS: filterS, + connMgr: connMgr, + attrSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}, + } + toDebit := utils.NewDecimal(10, 0) + if _, err := cb.debitUsage(toDebit, + new(utils.CGREvent)); err == nil || err.Error() != "RATES_ERROR:NOT_CONNECTED: RateS" { + t.Error(err) + } +} diff --git a/accounts/libaccounts.go b/accounts/libaccounts.go index aca694aad..6bf40838a 100644 --- a/accounts/libaccounts.go +++ b/accounts/libaccounts.go @@ -107,9 +107,12 @@ func processAttributeS(connMgr *engine.ConnManager, cgrEv *utils.CGREvent, AttributeIDs: attrIDs, ProcessRuns: procRuns, } - err = connMgr.Call(attrSConns, nil, utils.AttributeSv1ProcessEvent, - attrArgs, &rplyEv) - return + var tmpReply engine.AttrSProcessEventReply + if err = connMgr.Call(attrSConns, nil, utils.AttributeSv1ProcessEvent, + attrArgs, &tmpReply); err != nil { + return + } + return &tmpReply, nil } // rateSCostForEvent will process the event with RateS in order to get the cost @@ -118,9 +121,12 @@ func rateSCostForEvent(connMgr *engine.ConnManager, cgrEv *utils.CGREvent, if len(rateSConns) == 0 { return nil, utils.NewErrNotConnected(utils.RateS) } - err = connMgr.Call(rateSConns, nil, utils.RateSv1CostForEvent, - &utils.ArgsCostForEvent{CGREvent: cgrEv, RateProfileIDs: rpIDs}, &rplyCost) - return + var tmpReply engine.RateProfileCost + if err = connMgr.Call(rateSConns, nil, utils.RateSv1CostForEvent, + &utils.ArgsCostForEvent{CGREvent: cgrEv, RateProfileIDs: rpIDs}, &tmpReply); err != nil { + return + } + return &tmpReply, nil } // costIncrement computes the costIncrement for the event