diff --git a/accounts/abstractbalance_test.go b/accounts/abstractbalance_test.go index 82677b398..57020ff80 100644 --- a/accounts/abstractbalance_test.go +++ b/accounts/abstractbalance_test.go @@ -191,7 +191,7 @@ func TestABDebitUsage(t *testing.T) { } -func TestABCost0(t *testing.T) { +func TestABCost0WithConcrete(t *testing.T) { // consume units only from abstract balance aB := &abstractBalance{ blnCfg: &utils.Balance{ @@ -350,3 +350,186 @@ func TestABCost0WithUnlimited(t *testing.T) { t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) } } + +func TestABCost0WithUnlimitedWithConcrete(t *testing.T) { + // consume more units that has an abstract balance + aB := &abstractBalance{ + blnCfg: &utils.Balance{ + ID: "AB_COST_0", + Type: utils.MetaAbstract, + Units: utils.NewDecimal(int64(time.Duration(60*time.Second)), 0), // 1 Minute + Opts: map[string]interface{}{ + utils.MetaBalanceUnlimited: true, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: utils.NewDecimal(0, 0), + }, + }, + }, + cncrtBlncs: []*concreteBalance{ + { + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(10, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + + if ec, err := aB.debitUsage(utils.NewDecimal(int64(80*time.Second), 0), + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if ec.Usage.Cmp(decimal.New(int64(80*time.Second), 0)) != 0 { + t.Errorf("Unexpected debited units: %s", ec.Usage) + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(-int64(time.Duration(20*time.Second)), 0)) != 0 { + t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) + } else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(10, 0)) != 0 { + t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units) + } +} + +func TestABCost0WithLimit(t *testing.T) { + // consume more units that has an abstract balance + aB := &abstractBalance{ + blnCfg: &utils.Balance{ + ID: "AB_COST_0", + Type: utils.MetaAbstract, + Units: utils.NewDecimal(int64(time.Duration(60*time.Second)), 0), // 1 Minute + Opts: map[string]interface{}{ + utils.MetaBalanceLimit: 30000000000.0, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: utils.NewDecimal(0, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + + if ec, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0), + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if ec.Usage.Cmp(decimal.New(int64(30*time.Second), 0)) != 0 { + t.Errorf("Unexpected debited units: %s", ec.Usage) + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0)) != 0 { + t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) + } +} + +func TestABCost0WithLimitWithConcrete(t *testing.T) { + // consume more units that has an abstract balance + aB := &abstractBalance{ + blnCfg: &utils.Balance{ + ID: "AB_COST_0", + Type: utils.MetaAbstract, + Units: utils.NewDecimal(int64(time.Duration(60*time.Second)), 0), // 1 Minute + Opts: map[string]interface{}{ + utils.MetaBalanceLimit: 30000000000.0, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: utils.NewDecimal(0, 0), + }, + }, + }, + cncrtBlncs: []*concreteBalance{ + { + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(10, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + + if ec, err := aB.debitUsage(utils.NewDecimal(int64(30*time.Second), 0), + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if ec.Usage.Cmp(decimal.New(int64(30*time.Second), 0)) != 0 { + t.Errorf("Unexpected debited units: %s", ec.Usage) + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0)) != 0 { + t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) + } else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(10, 0)) != 0 { + t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units) + } +} + +func TestABCost0WithLimitExceed(t *testing.T) { + // consume more units that has an abstract balance + aB := &abstractBalance{ + blnCfg: &utils.Balance{ + ID: "AB_COST_0", + Type: utils.MetaAbstract, + Units: utils.NewDecimal(int64(time.Duration(60*time.Second)), 0), // 1 Minute + Opts: map[string]interface{}{ + utils.MetaBalanceLimit: 30000000000.0, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: utils.NewDecimal(0, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + + if ec, err := aB.debitUsage(utils.NewDecimal(int64(50*time.Second), 0), + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if ec.Usage.Cmp(decimal.New(int64(30*time.Second), 0)) != 0 { + t.Errorf("Unexpected debited units: %s", ec.Usage) + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0)) != 0 { + t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) + } +} + +func TestABCost0WithLimitExceedWithConcrete(t *testing.T) { + // consume more units that has an abstract balance + aB := &abstractBalance{ + blnCfg: &utils.Balance{ + ID: "AB_COST_0", + Type: utils.MetaAbstract, + Units: utils.NewDecimal(int64(time.Duration(60*time.Second)), 0), // 1 Minute + Opts: map[string]interface{}{ + utils.MetaBalanceLimit: 30000000000.0, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: utils.NewDecimal(0, 0), + }, + }, + }, + cncrtBlncs: []*concreteBalance{ + { + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + Units: utils.NewDecimal(10, 0), + }, + }, + }, + fltrS: new(engine.FilterS), + } + + if ec, err := aB.debitUsage(utils.NewDecimal(int64(50*time.Second), 0), + new(utils.CGREvent)); err != nil { + t.Error(err) + } else if ec.Usage.Cmp(decimal.New(int64(30*time.Second), 0)) != 0 { + t.Errorf("Unexpected debited units: %s", ec.Usage) + } else if aB.blnCfg.Units.Compare(utils.NewDecimal(int64(time.Duration(30*time.Second)), 0)) != 0 { + t.Errorf("Unexpected units in abstract balance: %s", aB.blnCfg.Units) + } else if aB.cncrtBlncs[0].blnCfg.Units.Compare(utils.NewDecimal(10, 0)) != 0 { + t.Errorf("Unexpected units in concrete balance: %s", aB.cncrtBlncs[0].blnCfg.Units) + } +} diff --git a/accounts/concretebalance_test.go b/accounts/concretebalance_test.go index 048797863..9bad1b752 100644 --- a/accounts/concretebalance_test.go +++ b/accounts/concretebalance_test.go @@ -416,3 +416,41 @@ func TestCBDebitWithUnitFactorWithFiltersWithLimit(t *testing.T) { t.Errorf("balance remaining: %s", cb.blnCfg.Units) } } + +func TestCBDebitWithMultipleUnitFactor(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 100 units from a balance ( the unit factor doesn't match ) + cb := &concreteBalance{ + blnCfg: &utils.Balance{ + ID: "CB", + Type: utils.MetaConcrete, + UnitFactors: []*utils.UnitFactor{ + &utils.UnitFactor{ + FilterIDs: []string{"*string:~*req.CustomField:CustomValue"}, + Factor: utils.NewDecimal(100, 0), + }, + &utils.UnitFactor{ + FilterIDs: []string{"*string:~*req.CustomField2:CustomValue2"}, + Factor: utils.NewDecimal(50, 0), + }, + }, + Units: utils.NewDecimal(500, 0), // 500 Units + }, + fltrS: filterS, + } + mp := utils.MapStorage{} + mp.Set([]string{utils.MetaReq}, map[string]interface{}{ + "CustomField2": "CustomValue2", + }) + if dbted, _, err := cb.debitUnits(utils.NewDecimal(3, 0), + "cgrates.org", mp); err != nil { + t.Error(err) + } else if dbted.Compare(utils.NewDecimal(3, 0)) != 0 { + t.Errorf("debited: %s", dbted) + } else if cb.blnCfg.Units.Cmp(decimal.New(350, 0)) != 0 { + t.Errorf("balance remaining: %s", cb.blnCfg.Units) + } +}