most engine tests passing

ResetAccountPending
This commit is contained in:
Radu Ioan Fericean
2016-02-15 23:05:35 +02:00
parent b2253e6385
commit 418a9cf12f
17 changed files with 746 additions and 501 deletions

View File

@@ -22,7 +22,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"time"
"github.com/cgrates/cgrates/cache2go"
@@ -258,6 +257,7 @@ func (ub *Account) debitBalanceAction(a *Action, reset bool) error {
return err
}
}
ub.InitCounters()
ub.ExecuteActionTriggers(nil)
return nil
}
@@ -588,22 +588,27 @@ func (acc *Account) ExecuteActionTriggers(a *Action) {
// the next reset (see RESET_TRIGGERS action type)
continue
}
if !at.Match(a) {
continue
}
if strings.Contains(at.ThresholdType, "counter") {
for _, uc := range acc.UnitCounters {
if uc.BalanceType == at.Balance.GetType() &&
strings.Contains(at.ThresholdType, uc.CounterType[1:]) {
for _, b := range uc.Balances {
if strings.HasPrefix(at.ThresholdType, "*max") {
if b.MatchActionTrigger(at) && b.GetValue() >= at.ThresholdValue {
at.Execute(acc, nil)
}
} else { //MIN
if b.MatchActionTrigger(at) && b.GetValue() <= at.ThresholdValue {
at.Execute(acc, nil)
if (at.Balance.ID == nil || *at.Balance.ID != "") && at.UniqueID != "" {
at.Balance.ID = utils.StringPointer(at.UniqueID)
}
for _, counters := range acc.UnitCounters {
for _, uc := range counters {
if strings.Contains(at.ThresholdType, uc.CounterType[1:]) {
for _, c := range uc.Counters {
//log.Print("C: ", utils.ToJSON(c))
if strings.HasPrefix(at.ThresholdType, "*max") {
if c.Filter.Equal(at.Balance) && c.Value >= at.ThresholdValue {
//log.Print("HERE")
at.Execute(acc, nil)
}
} else { //MIN
if c.Filter.Equal(at.Balance) && c.Value <= at.ThresholdValue {
at.Execute(acc, nil)
}
}
}
}
@@ -643,7 +648,7 @@ func (acc *Account) ResetActionTriggers(a *Action) {
}
at.Executed = false
}
acc.ExecuteActionTriggers(a)
acc.ExecuteActionTriggers(a) //will trigger infinite loop when executed from ExecuteActionTriggers
}
// Sets/Unsets recurrent flag for action triggers
@@ -665,9 +670,10 @@ func (acc *Account) countUnits(amount float64, kind string, cc *CallCost, b *Bal
// Create counters for all triggered actions
func (acc *Account) InitCounters() {
oldUcs := acc.UnitCounters
acc.UnitCounters = nil
acc.UnitCounters = make(UnitCounters)
ucTempMap := make(map[string]*UnitCounter)
for _, at := range acc.ActionTriggers {
//log.Print("AT: ", utils.ToJSON(at))
if !strings.Contains(at.ThresholdType, "counter") {
continue
}
@@ -675,28 +681,36 @@ func (acc *Account) InitCounters() {
if strings.Contains(at.ThresholdType, "balance") {
ct = utils.COUNTER_BALANCE
}
log.Print(at.Balance.GetType() + ct)
uc, exists := ucTempMap[at.Balance.GetType()+ct]
//log.Print("CT: ", at.Balance.GetType()+ct)
if !exists {
log.Print("HERE!")
uc = &UnitCounter{
BalanceType: at.Balance.GetType(),
CounterType: ct,
}
ucTempMap[at.Balance.GetType()+ct] = uc
uc.Balances = BalanceChain{}
acc.UnitCounters = append(acc.UnitCounters, uc)
uc.Counters = make(CounterFilters, 0)
acc.UnitCounters[at.Balance.GetType()] = append(acc.UnitCounters[at.Balance.GetType()], uc)
}
b := at.Balance.CreateBalance()
if !uc.Balances.HasBalance(b) {
uc.Balances = append(uc.Balances, b)
c := &CounterFilter{Filter: at.Balance}
if (c.Filter.ID == nil || *c.Filter.ID == "") && at.UniqueID != "" {
c.Filter.ID = utils.StringPointer(at.UniqueID)
}
//log.Print("C: ", utils.ToJSON(c))
if !uc.Counters.HasCounter(c) {
uc.Counters = append(uc.Counters, c)
}
}
// copy old counter values
for _, uc := range acc.UnitCounters {
for _, oldUc := range oldUcs {
if uc.CopyCounterValues(oldUc) {
break
for key, counters := range acc.UnitCounters {
oldCounters, found := oldUcs[key]
if !found {
continue
}
for _, uc := range counters {
for _, oldUc := range oldCounters {
if uc.CopyCounterValues(oldUc) {
break
}
}
}
}
@@ -908,30 +922,32 @@ func (acc *Account) AsOldStructure() interface{} {
AllowNegative: acc.AllowNegative,
Disabled: acc.Disabled,
}
for i, uc := range acc.UnitCounters {
if uc == nil {
continue
}
result.UnitCounters[i] = &UnitsCounter{
BalanceType: uc.BalanceType,
Balances: make(BalanceChain, len(uc.Balances)),
}
if len(uc.Balances) > 0 {
result.UnitCounters[i].Direction = uc.Balances[0].Directions.String()
for j, b := range uc.Balances {
result.UnitCounters[i].Balances[j] = &Balance{
Uuid: b.Uuid,
Id: b.Id,
Value: b.Value,
ExpirationDate: b.ExpirationDate,
Weight: b.Weight,
DestinationIds: b.DestinationIds.String(),
RatingSubject: b.RatingSubject,
Category: b.Categories.String(),
SharedGroup: b.SharedGroups.String(),
Timings: b.Timings,
TimingIDs: b.TimingIDs.String(),
Disabled: b.Disabled,
for balanceType, counters := range acc.UnitCounters {
for i, uc := range counters {
if uc == nil {
continue
}
result.UnitCounters[i] = &UnitsCounter{
BalanceType: balanceType,
Balances: make(BalanceChain, len(uc.Counters)),
}
if len(uc.Counters) > 0 {
result.UnitCounters[i].Direction = (*uc.Counters[0].Filter.Directions).String()
for j, c := range uc.Counters {
result.UnitCounters[i].Balances[j] = &Balance{
Uuid: c.Filter.GetUuid(),
Id: c.Filter.GetID(),
Value: c.Filter.GetValue(),
ExpirationDate: c.Filter.GetExpirationDate(),
Weight: c.Filter.GetWeight(),
DestinationIds: c.Filter.GetDestinationIDs().String(),
RatingSubject: c.Filter.GetRatingSubject(),
Category: c.Filter.GetCategories().String(),
SharedGroup: c.Filter.GetSharedGroups().String(),
Timings: c.Filter.Timings,
TimingIDs: c.Filter.GetTimingIDs().String(),
Disabled: c.Filter.GetDisabled(),
}
}
}
}

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"log"
"testing"
"time"
@@ -817,12 +816,12 @@ func TestAccountdebitBalance(t *testing.T) {
newMb := &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Weight: utils.Float64Pointer(20),
DestinationIds: utils.StringMapPointer(utils.StringMap{"NEW": true}),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NEW": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
a := &Action{Balance: newMb}
ub.debitBalanceAction(a, false)
if len(ub.BalanceMap[utils.VOICE]) != 3 || !ub.BalanceMap[utils.VOICE][2].DestinationIds.Equal(*newMb.DestinationIds) {
if len(ub.BalanceMap[utils.VOICE]) != 3 || !ub.BalanceMap[utils.VOICE][2].DestinationIds.Equal(*newMb.DestinationIDs) {
t.Errorf("Error adding minute bucket! %d %+v %+v", len(ub.BalanceMap[utils.VOICE]), ub.BalanceMap[utils.VOICE][2], newMb)
}
}
@@ -860,7 +859,7 @@ func TestAccountdebitBalanceExists(t *testing.T) {
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
Weight: utils.Float64Pointer(20),
DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
a := &Action{Balance: newMb}
@@ -886,19 +885,19 @@ func TestAccountAddMinutBucketEmpty(t *testing.T) {
mb1 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb2 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
DestinationIds: utils.StringMapPointer(utils.StringMap{"NAT": true}),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"NAT": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
mb3 := &BalanceFilter{
Value: utils.Float64Pointer(-10),
Type: utils.StringPointer(utils.VOICE),
DestinationIds: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
DestinationIDs: utils.StringMapPointer(utils.StringMap{"OTHER": true}),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
}
ub := &Account{}
@@ -923,7 +922,7 @@ func TestAccountExecuteTriggeredActions(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}, Directions: utils.StringMap{utils.OUT: true}}, &Balance{Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.StringMap{utils.OUT: true}}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.StringMap{utils.OUT: true})}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
@@ -947,7 +946,7 @@ func TestAccountExecuteTriggeredActionsBalance(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 10, Weight: 20, DestinationIds: utils.StringMap{"NAT": true}}, &Balance{Directions: utils.NewStringMap(utils.OUT), Weight: 10, DestinationIds: utils.StringMap{"RET": true}}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Filter: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, Value: 1.0}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"}},
}
ub.countUnits(1, utils.MONETARY, nil, nil)
@@ -960,14 +959,14 @@ func TestAccountExecuteTriggeredActionsOrder(t *testing.T) {
ub := &Account{
Id: "TEST_UB_OREDER",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Type: utils.StringPointer(utils.MONETARY)}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS_ORDER"}},
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.BalanceMap[utils.MONETARY]) != 1 || ub.BalanceMap[utils.MONETARY][0].GetValue() != 10 {
t.Errorf("Error executing triggered actions in order %v BAL: %+v", ub.BalanceMap[utils.MONETARY][0].GetValue(), ub.BalanceMap[utils.MONETARY][1])
t.Errorf("Error executing triggered actions in order %v", ub.BalanceMap[utils.MONETARY][0].GetValue())
}
}
@@ -980,24 +979,22 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) {
&ActionTrigger{UniqueID: "week_trigger", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 100, ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ActionsId: "TEST_ACTIONS"},
},
}
log.Print("==============")
ub.InitCounters()
log.Print("==============")
if len(ub.UnitCounters) != 1 || len(ub.UnitCounters[0].Balances) != 2 {
log.Print("Error initializing counters: ", ub.UnitCounters[0].Balances[0])
if len(ub.UnitCounters) != 1 || len(ub.UnitCounters[utils.MONETARY][0].Counters) != 2 {
t.Error("Error initializing counters: ", ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
ub.countUnits(1, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if ub.UnitCounters[0].Balances[0].Value != 1 ||
ub.UnitCounters[0].Balances[1].Value != 1 {
t.Error("Error incrementing both counters", ub.UnitCounters[0].Balances[0].Value, ub.UnitCounters[0].Balances[1].Value)
if ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 1 ||
ub.UnitCounters[utils.MONETARY][0].Counters[1].Value != 1 {
t.Error("Error incrementing both counters", ub.UnitCounters[utils.MONETARY][0].Counters[0].Value, ub.UnitCounters[utils.MONETARY][0].Counters[1].Value)
}
// we can reset them
resetCountersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("day_trigger")}}, nil)
if ub.UnitCounters[0].Balances[0].Value != 0 ||
ub.UnitCounters[0].Balances[1].Value != 1 {
t.Error("Error reseting both counters", ub.UnitCounters[0].Balances[0].Value, ub.UnitCounters[0].Balances[1].Value)
resetCountersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("day_trigger")}}, nil)
if ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 0 ||
ub.UnitCounters[utils.MONETARY][0].Counters[1].Value != 1 {
t.Error("Error reseting both counters", ub.UnitCounters[utils.MONETARY][0].Counters[0].Value, ub.UnitCounters[utils.MONETARY][0].Counters[1].Value)
}
}
@@ -1087,45 +1084,45 @@ func TestCleanExpired(t *testing.T) {
}
func TestAccountUnitCounting(t *testing.T) {
ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0}}}}}
ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
}
func TestAccountUnitCountingOutbound(t *testing.T) {
ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: utils.NewStringMap(utils.OUT)}}}}}
ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 30 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 30 {
t.Error("Error counting units")
}
}
func TestAccountUnitCountingOutboundInbound(t *testing.T) {
ub := &Account{UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 0, Directions: utils.NewStringMap(utils.OUT)}}}}}
ub := &Account{UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 0, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}}}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 10 {
t.Errorf("Error counting units: %+v", ub.UnitCounters[0].Balances[0])
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 {
t.Errorf("Error counting units: %+v", ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.OUT}, nil)
if len(ub.UnitCounters) != 1 && ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20 {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
ub.countUnits(10, utils.MONETARY, &CallCost{Direction: utils.IN}, nil)
if len(ub.UnitCounters) != 1 || (ub.UnitCounters[0].BalanceType != utils.MONETARY || ub.UnitCounters[0].Balances[0].GetValue() != 20) {
if len(ub.UnitCounters[utils.MONETARY]) != 1 || ub.UnitCounters[utils.MONETARY][0].Counters[0].Value != 20 {
t.Error("Error counting units")
}
}
@@ -1654,15 +1651,18 @@ func TestAccountInitCounters(t *testing.T) {
},
}
a.InitCounters()
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
len(a.UnitCounters[1].Balances) != 1 ||
len(a.UnitCounters[2].Balances) != 1 ||
len(a.UnitCounters[3].Balances) != 1 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
len(a.UnitCounters[utils.VOICE][0].Counters) != 1 ||
len(a.UnitCounters[utils.VOICE][1].Counters) != 1 ||
len(a.UnitCounters[utils.SMS][0].Counters) != 1 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, c := range uc.Counters {
t.Logf("B: %+v", c)
}
}
}
t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters))
@@ -1730,15 +1730,18 @@ func TestAccountDoubleInitCounters(t *testing.T) {
}
a.InitCounters()
a.InitCounters()
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
len(a.UnitCounters[1].Balances) != 1 ||
len(a.UnitCounters[2].Balances) != 1 ||
len(a.UnitCounters[3].Balances) != 1 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
len(a.UnitCounters[utils.VOICE][0].Counters) != 1 ||
len(a.UnitCounters[utils.VOICE][1].Counters) != 1 ||
len(a.UnitCounters[utils.SMS][0].Counters) != 1 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, c := range uc.Counters {
t.Logf("B: %+v", c)
}
}
}
t.Errorf("Error Initializing unit counters: %v", len(a.UnitCounters))

View File

@@ -48,134 +48,6 @@ type Action struct {
Balance *BalanceFilter
}
type BalanceFilter struct {
Uuid *string
Id *string
Type *string
Value *float64
Directions *utils.StringMap
ExpirationDate *time.Time
Weight *float64
DestinationIds *utils.StringMap
RatingSubject *string
Categories *utils.StringMap
SharedGroups *utils.StringMap
TimingIDs *utils.StringMap
Timings []*RITiming
Disabled *bool
Factor *ValueFactor
Blocker *bool
}
func (bp *BalanceFilter) CreateBalance() *Balance {
b := &Balance{}
if bp.Uuid != nil {
b.Uuid = *bp.Uuid
}
if bp.Id != nil {
b.Id = *bp.Id
}
if bp.Value != nil {
b.Value = *bp.Value
}
if bp.Directions != nil {
b.Directions = *bp.Directions
}
if bp.ExpirationDate != nil {
b.ExpirationDate = *bp.ExpirationDate
}
if bp.Weight != nil {
b.Weight = *bp.Weight
}
if bp.DestinationIds != nil {
b.DestinationIds = *bp.DestinationIds
}
if bp.RatingSubject != nil {
b.RatingSubject = *bp.RatingSubject
}
if bp.Categories != nil {
b.Categories = *bp.Categories
}
if bp.SharedGroups != nil {
b.SharedGroups = *bp.SharedGroups
}
if bp.TimingIDs != nil {
b.TimingIDs = *bp.TimingIDs
}
if bp.Disabled != nil {
b.Disabled = *bp.Disabled
}
if bp.Factor != nil {
b.Factor = *bp.Factor
}
if bp.Blocker != nil {
b.Blocker = *bp.Blocker
}
return b.Clone()
}
func (bp *BalanceFilter) LoadFromBalance(b *Balance) {
if b.Uuid != "" {
bp.Uuid = &b.Uuid
}
if b.Id != "" {
bp.Id = &b.Id
}
if b.Value != 0 {
bp.Value = &b.Value
}
if len(b.Directions) != 0 {
bp.Directions = &b.Directions
}
if !b.ExpirationDate.IsZero() {
bp.ExpirationDate = &b.ExpirationDate
}
if b.Weight != 0 {
bp.Weight = &b.Weight
}
if len(b.DestinationIds) != 0 {
bp.DestinationIds = &b.DestinationIds
}
if b.RatingSubject != "" {
bp.RatingSubject = &b.RatingSubject
}
if len(b.Categories) != 0 {
bp.Categories = &b.Categories
}
if len(b.SharedGroups) != 0 {
bp.SharedGroups = &b.SharedGroups
}
if len(b.TimingIDs) != 0 {
bp.TimingIDs = &b.TimingIDs
}
if len(b.Factor) != 0 {
bp.Factor = &b.Factor
}
bp.Disabled = &b.Disabled
bp.Blocker = &b.Blocker
}
func (bp *BalanceFilter) GetType() string {
if bp.Type == nil {
return ""
}
return *bp.Type
}
func (bp *BalanceFilter) GetValue() float64 {
if bp.Value == nil {
return 0.0
}
return *bp.Value
}
func (bp *BalanceFilter) SetValue(v float64) {
if bp.Value == nil {
bp.Value = new(float64)
}
*bp.Value = v
}
const (
LOG = "*log"
RESET_TRIGGERS = "*reset_triggers"
@@ -301,7 +173,7 @@ func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action)
case "AccountID":
parsedValue += rsrFld.ParseValue(acnt.Id)
case "Directions":
parsedValue += rsrFld.ParseValue(action.Balance.Directions.String())
parsedValue += rsrFld.ParseValue(b.Directions.String())
case utils.TENANT:
parsedValue += rsrFld.ParseValue(dta.Tenant)
case utils.ACCOUNT:

View File

@@ -307,7 +307,7 @@ func (at *ActionTiming) Execute() (err error) {
continue // disabled acocunts are not removed from action plan
//return 0, fmt.Errorf("Account %s is disabled", accID)
}
if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) && parseErr == nil && !expDate.IsZero() {
if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.HasExpirationDate()) && parseErr == nil && !expDate.IsZero() {
a.Balance.ExpirationDate = &time.Time{}
*a.Balance.ExpirationDate = expDate
}
@@ -337,8 +337,7 @@ func (at *ActionTiming) Execute() (err error) {
}
if len(at.accountIDs) == 0 { // action timing executing without accounts
for _, a := range aac {
if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) &&
if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.HasExpirationDate()) &&
parseErr == nil && !expDate.IsZero() {
a.Balance.ExpirationDate = &time.Time{}
*a.Balance.ExpirationDate = expDate

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"encoding/json"
"fmt"
"sort"
"time"
@@ -112,10 +113,37 @@ func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err erro
// returns true if the field of the action timing are equeal to the non empty
// fields of the action
func (at *ActionTrigger) Match(a *Action) bool {
if a == nil {
if a == nil || a.Balance == nil {
return true
}
return at.Balance.CreateBalance().MatchFilter(a.Balance, false)
if a.Balance.Type != nil && a.Balance.GetType() != at.Balance.GetType() {
return false
}
var thresholdType bool
if a.ExtraParameters != "" {
t := struct {
GroupID string
UniqueID string
ThresholdType string
}{}
json.Unmarshal([]byte(a.ExtraParameters), &t)
// check Ids first
if t.GroupID != "" {
return at.ID == t.GroupID
}
if t.UniqueID != "" {
return at.UniqueID == t.UniqueID
}
thresholdType = t.ThresholdType == "" || at.ThresholdType == t.ThresholdType
}
return thresholdType && at.Balance.CreateBalance().MatchFilter(a.Balance, false)
}
func (at *ActionTrigger) CreateBalance() *Balance {
b := at.Balance.CreateBalance()
b.Id = at.UniqueID
return b
}
// makes a shallow copy of the receiver

View File

@@ -613,7 +613,7 @@ func TestActionTriggerMatchSomeFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_BALANCE, 2)}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%s"}`, utils.TRIGGER_MAX_BALANCE_COUNTER)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -628,7 +628,7 @@ func TestActionTriggerMatcBalanceFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*out"}`, utils.TRIGGER_MAX_BALANCE, 3.0)}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ExtraParameters: fmt.Sprintf(`{"GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -643,7 +643,7 @@ func TestActionTriggerMatcAllFalse(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v, "BalanceDirections":"*in"}`, utils.TRIGGER_MAX_EVENT_COUNTER, 3)}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"%s", "ThresholdType":"%s"}`, "TEST", utils.TRIGGER_MAX_BALANCE)}
if at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -651,18 +651,28 @@ func TestActionTriggerMatcAllFalse(t *testing.T) {
func TestActionTriggerMatchAll(t *testing.T) {
at := &ActionTrigger{
ID: "TEST",
UniqueID: "ZIP",
ThresholdType: "TT",
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
RatingSubject: utils.StringPointer("test1"),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(2),
Weight: utils.Float64Pointer(1.0),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
},
ThresholdType: utils.TRIGGER_MAX_BALANCE,
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ExtraParameters: fmt.Sprintf(`{"BalanceDirections":"*out", "ThresholdType":"%v", "ThresholdValue": %v, "DestinationIds": "%v", "BalanceWeight": %v, "BalanceRatingSubject": "%v", "BalanceSharedGroup": "%v"}`, utils.TRIGGER_MAX_BALANCE, 2, "NAT", 1.0, "test1", "test2")}
a := &Action{Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
RatingSubject: utils.StringPointer("test1"),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(2),
Weight: utils.Float64Pointer(1.0),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
}, ExtraParameters: fmt.Sprintf(`{"UniqueID":"ZIP", "GroupID":"TEST", "ThresholdType":"TT"}`)}
if !at.Match(a) {
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
}
@@ -684,7 +694,7 @@ func TestActionResetTriggres(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, nil, nil)
@@ -697,7 +707,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, nil, nil)
@@ -710,7 +720,7 @@ func TestActionResetTriggresActionFilter(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 10}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetTriggersAction(ub, nil, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}}, nil)
@@ -723,7 +733,7 @@ func TestActionSetPostpaid(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
allowNegativeAction(ub, nil, nil, nil)
@@ -737,7 +747,7 @@ func TestActionSetPrepaid(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
denyNegativeAction(ub, nil, nil, nil)
@@ -751,7 +761,7 @@ func TestActionResetPrepaid(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetAccountAction(ub, nil, nil, nil)
@@ -761,7 +771,7 @@ func TestActionResetPrepaid(t *testing.T) {
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
t.Log(ub.BalanceMap)
t.Error("Reset prepaid action failed!")
t.Error("Reset account action failed!")
}
}
@@ -769,7 +779,7 @@ func TestActionResetPostpaid(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
resetAccountAction(ub, nil, nil, nil)
@@ -777,7 +787,7 @@ func TestActionResetPostpaid(t *testing.T) {
len(ub.UnitCounters) != 0 ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
t.Error("Reset postpaid action failed!")
t.Error("Reset account action failed!")
}
}
@@ -785,17 +795,17 @@ func TestActionTopupResetCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Directions: utils.NewStringMap(utils.OUT), Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 10 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 || // InitCounters finds no counters
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Errorf("Topup reset action failed: %+v", ub.BalanceMap[utils.MONETARY][0])
t.Errorf("Topup reset action failed: %+s", utils.ToIJSON(ub))
}
}
@@ -828,7 +838,7 @@ func TestActionTopupResetCreditId(t *testing.T) {
},
},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Id: utils.StringPointer("TEST_B"), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), ID: utils.StringPointer("TEST_B"), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
@@ -862,15 +872,15 @@ func TestActionTopupResetMinutes(t *testing.T) {
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{&Balance{Value: 100}},
utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupResetAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 5 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Errorf("Topup reset minutes action failed: %+v", ub.BalanceMap[utils.VOICE][0])
@@ -881,14 +891,14 @@ func TestActionTopupCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Topup action failed!", ub.BalanceMap[utils.MONETARY].GetTotalValue())
@@ -899,15 +909,15 @@ func TestActionTopupMinutes(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
topupAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE].GetTotalValue() != 15 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Topup minutes action failed!", ub.BalanceMap[utils.VOICE])
@@ -918,17 +928,17 @@ func TestActionDebitCredit(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 90 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Debit action failed!", ub.BalanceMap[utils.MONETARY].GetTotalValue())
t.Error("Debit action failed!", utils.ToIJSON(ub))
}
}
@@ -936,15 +946,15 @@ func TestActionDebitMinutes(t *testing.T) {
ub := &Account{
Id: "TEST_UB",
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}, &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Value: utils.Float64Pointer(5), Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}
debitAction(ub, nil, a, nil)
if ub.AllowNegative ||
ub.BalanceMap[utils.VOICE][0].GetValue() != 5 ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters) != 0 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true || ub.ActionTriggers[1].Executed != true {
t.Error("Debit minutes action failed!", ub.BalanceMap[utils.VOICE][0])
@@ -961,24 +971,24 @@ func TestActionResetAllCounters(t *testing.T) {
&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT"), Directions: utils.NewStringMap(utils.OUT)},
&Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT)}}},
ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")), Weight: utils.Float64Pointer(20)}, ActionsId: "TEST_ACTIONS", Executed: true}},
ActionTriggers: ActionTriggers{&ActionTrigger{ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2, Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Weight: utils.Float64Pointer(20)}, ActionsId: "TEST_ACTIONS", Executed: true}},
}
ub.InitCounters()
resetCountersAction(ub, nil, nil, nil)
if !ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters[0].Balances) != 1 ||
len(ub.UnitCounters[utils.MONETARY][0].Counters) != 1 ||
len(ub.BalanceMap[utils.MONETARY]) != 1 ||
ub.ActionTriggers[0].Executed != true {
t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[0], ub.UnitCounters[0].Balances[0])
t.Errorf("Reset counters action failed: %+v %+v %+v", ub.UnitCounters, ub.UnitCounters[utils.MONETARY][0], ub.UnitCounters[utils.MONETARY][0].Counters[0])
}
if len(ub.UnitCounters) < 1 {
t.FailNow()
}
mb := ub.UnitCounters[0].Balances[0]
if mb.Weight != 20 || mb.GetValue() != 0 || mb.DestinationIds["NAT"] == false {
t.Errorf("Balance cloned incorrectly: %+v", mb)
c := ub.UnitCounters[utils.MONETARY][0].Counters[0]
if c.Filter.GetWeight() != 20 || c.Value != 0 || c.Filter.GetDestinationIDs()["NAT"] == false {
t.Errorf("Balance cloned incorrectly: %+v", c)
}
}
@@ -997,20 +1007,20 @@ func TestActionResetCounterOnlyDefault(t *testing.T) {
if !ub.AllowNegative ||
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
len(ub.UnitCounters) != 1 ||
len(ub.UnitCounters[0].Balances) != 1 ||
len(ub.UnitCounters[utils.MONETARY][0].Counters) != 1 ||
len(ub.BalanceMap[utils.VOICE]) != 2 ||
ub.ActionTriggers[0].Executed != true {
for _, b := range ub.UnitCounters[0].Balances {
for _, b := range ub.UnitCounters[utils.MONETARY][0].Counters {
t.Logf("B: %+v", b)
}
t.Errorf("Reset counters action failed: %+v", ub.UnitCounters)
}
if len(ub.UnitCounters) < 1 || len(ub.UnitCounters[0].Balances) < 1 {
if len(ub.UnitCounters) < 1 || len(ub.UnitCounters[utils.MONETARY][0].Counters) < 1 {
t.FailNow()
}
mb := ub.UnitCounters[0].Balances[0]
if mb.Weight != 0 || mb.GetValue() != 0 || len(mb.DestinationIds) != 0 {
t.Errorf("Balance cloned incorrectly: %+v!", mb)
c := ub.UnitCounters[utils.MONETARY][0].Counters[0]
if c.Filter.GetWeight() != 0 || c.Value != 0 || len(c.Filter.GetDestinationIDs()) != 0 {
t.Errorf("Balance cloned incorrectly: %+v!", c)
}
}
@@ -1019,7 +1029,7 @@ func TestActionResetCounterCredit(t *testing.T) {
Id: "TEST_UB",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.MONETARY: BalanceChain{&Balance{Value: 100}}, utils.VOICE: BalanceChain{&Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{&UnitCounter{BalanceType: utils.MONETARY, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}, &UnitCounter{BalanceType: utils.SMS, Balances: BalanceChain{&Balance{Value: 1, Directions: utils.NewStringMap(utils.OUT)}}}},
UnitCounters: UnitCounters{utils.MONETARY: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}, utils.SMS: []*UnitCounter{&UnitCounter{Counters: CounterFilters{&CounterFilter{Value: 1, Filter: &BalanceFilter{Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}}}}}},
ActionTriggers: ActionTriggers{&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT))}, ThresholdValue: 2, ActionsId: "TEST_ACTIONS", Executed: true}},
}
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}}
@@ -1039,7 +1049,7 @@ func TestActionTriggerLogging(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
},
ThresholdValue: 100.0,
Weight: 10.0,
@@ -1142,7 +1152,7 @@ func TestTopupAction(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minu")
a := &Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1163,7 +1173,7 @@ func TestTopupActionLoaded(t *testing.T) {
initialUb, _ := accountingStorage.GetAccount("vdf:minitsboy")
a := &Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Weight: utils.Float64Pointer(20)},
}
at := &ActionTiming{
@@ -1190,7 +1200,7 @@ func TestActionCdrlogEmpty(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1212,11 +1222,11 @@ func TestActionCdrlogWithParams(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1239,11 +1249,11 @@ func TestActionCdrLogParamsWithOverload(t *testing.T) {
err := cdrLogAction(acnt, nil, cdrlog, Actions{
&Action{
ActionType: DEBIT,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
&Action{
ActionType: DEBIT_RESET,
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
Balance: &BalanceFilter{Value: utils.Float64Pointer(25), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")), Weight: utils.Float64Pointer(20)},
},
})
if err != nil {
@@ -1373,7 +1383,43 @@ func TestActionTransactionBalanceType(t *testing.T) {
if err != nil || acc == nil {
t.Error("Error getting account: ", acc, err)
}
if acc.BalanceMap[utils.MONETARY][0].Value != 10 {
if acc.BalanceMap[utils.MONETARY][0].Value != 11.1 {
t.Errorf("Transaction didn't work: %v", acc.BalanceMap[utils.MONETARY][0].Value)
}
}
func TestActionTransactionBalanceNotType(t *testing.T) {
err := accountingStorage.SetAccount(&Account{
Id: "cgrates.org:trans",
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{&Balance{
Value: 10,
}},
},
})
if err != nil {
t.Error("Error setting account: ", err)
}
at := &ActionTiming{
accountIDs: utils.StringMap{"cgrates.org:trans": true},
Timing: &RateInterval{},
actions: []*Action{
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Value: utils.Float64Pointer(1.1), Type: utils.StringPointer(utils.VOICE)},
},
&Action{
ActionType: TOPUP,
Balance: &BalanceFilter{Type: utils.StringPointer("test")},
},
},
}
err = at.Execute()
acc, err := accountingStorage.GetAccount("cgrates.org:trans")
if err != nil || acc == nil {
t.Error("Error getting account: ", acc, err)
}
if acc.BalanceMap[utils.MONETARY][0].Value != 10.0 {
t.Errorf("Transaction didn't work: %v", acc.BalanceMap[utils.MONETARY][0].Value)
}
}
@@ -1453,7 +1499,7 @@ func TestActionRemoveBalance(t *testing.T) {
ActionType: REMOVE_BALANCE,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")),
},
},
},
@@ -1850,43 +1896,58 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) {
}
a1 := &Action{
ActionType: "*enable_disable_balance",
ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*sms"),
Weight: utils.Float64Pointer(10),
ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"),
Disabled: utils.BoolPointer(true),
},
Weight: 9,
}
a2 := &Action{
ActionType: "*enable_disable_balance",
ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*sms"),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
ID: utils.StringPointer("for_v3hsillmilld500m_mms_ill"),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
Weight: 8,
}
a3 := &Action{
ActionType: "*enable_disable_balance",
ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*sms"),
ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
Weight: 8,
}
a4 := &Action{
ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*data"),
Uuid: utils.StringPointer("fc927edb-1bd6-425e-a2a3-9fd8bafaa524"),
RatingSubject: utils.StringPointer("for_v3hsillmilld500m_data_forfait"),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
Weight: 7,
}
a4 := &Action{
ActionType: "*enable_disable_balance",
a5 := &Action{
ActionType: "*set_balance",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &BalanceFilter{
Type: utils.StringPointer("*voice"),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
ID: utils.StringPointer("for_v3hsillmilld500m_voice_3_h"),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
Weight: utils.Float64Pointer(10),
Disabled: utils.BoolPointer(true),
},
@@ -1895,7 +1956,7 @@ func TestActionConditionalDisabledIfNegative(t *testing.T) {
at := &ActionTiming{
accountIDs: utils.StringMap{"cgrates.org:af": true},
actions: Actions{a1, a2, a3, a4},
actions: Actions{a1, a2, a3, a4, a5},
}
at.Execute()
@@ -1957,7 +2018,7 @@ func TestActionSetBalance(t *testing.T) {
a := &Action{
ActionType: SET_BALANCE,
Balance: &BalanceFilter{
Id: utils.StringPointer("m2"),
ID: utils.StringPointer("m2"),
Type: utils.StringPointer(utils.MONETARY),
Value: utils.Float64Pointer(11),
Weight: utils.Float64Pointer(10),

220
engine/balance_filter.go Normal file
View File

@@ -0,0 +1,220 @@
package engine
import (
"reflect"
"time"
"github.com/cgrates/cgrates/utils"
)
type BalanceFilter struct {
Uuid *string
ID *string
Type *string
Value *float64
Directions *utils.StringMap
ExpirationDate *time.Time
Weight *float64
DestinationIDs *utils.StringMap
RatingSubject *string
Categories *utils.StringMap
SharedGroups *utils.StringMap
TimingIDs *utils.StringMap
Timings []*RITiming
Disabled *bool
Factor *ValueFactor
Blocker *bool
}
func (bp *BalanceFilter) CreateBalance() *Balance {
b := &Balance{
Uuid: bp.GetUuid(),
Id: bp.GetID(),
Value: bp.GetValue(),
Directions: bp.GetDirections(),
ExpirationDate: bp.GetExpirationDate(),
Weight: bp.GetWeight(),
DestinationIds: bp.GetDestinationIDs(),
RatingSubject: bp.GetRatingSubject(),
Categories: bp.GetCategories(),
SharedGroups: bp.GetSharedGroups(),
Timings: bp.Timings,
TimingIDs: bp.GetTimingIDs(),
Disabled: bp.GetDisabled(),
Factor: bp.GetFactor(),
Blocker: bp.GetBlocker(),
}
return b.Clone()
}
func (bp *BalanceFilter) LoadFromBalance(b *Balance) *BalanceFilter {
if b.Uuid != "" {
bp.Uuid = &b.Uuid
}
if b.Id != "" {
bp.ID = &b.Id
}
if b.Value != 0 {
bp.Value = &b.Value
}
if len(b.Directions) != 0 {
bp.Directions = &b.Directions
}
if !b.ExpirationDate.IsZero() {
bp.ExpirationDate = &b.ExpirationDate
}
if b.Weight != 0 {
bp.Weight = &b.Weight
}
if len(b.DestinationIds) != 0 {
bp.DestinationIDs = &b.DestinationIds
}
if b.RatingSubject != "" {
bp.RatingSubject = &b.RatingSubject
}
if len(b.Categories) != 0 {
bp.Categories = &b.Categories
}
if len(b.SharedGroups) != 0 {
bp.SharedGroups = &b.SharedGroups
}
if len(b.TimingIDs) != 0 {
bp.TimingIDs = &b.TimingIDs
}
if len(b.Factor) != 0 {
bp.Factor = &b.Factor
}
if b.Disabled {
bp.Disabled = &b.Disabled
}
if b.Blocker {
bp.Blocker = &b.Blocker
}
return bp
}
func (bp *BalanceFilter) Equal(o *BalanceFilter) bool {
if bp.ID != nil && o.ID != nil {
return *bp.ID == *o.ID
}
return reflect.DeepEqual(bp, o)
}
func (bp *BalanceFilter) GetType() string {
if bp == nil || bp.Type == nil {
return ""
}
return *bp.Type
}
func (bp *BalanceFilter) GetValue() float64 {
if bp == nil || bp.Value == nil {
return 0.0
}
return *bp.Value
}
func (bp *BalanceFilter) SetValue(v float64) {
if bp.Value == nil {
bp.Value = new(float64)
}
*bp.Value = v
}
func (bp *BalanceFilter) GetUuid() string {
if bp == nil || bp.Uuid == nil {
return ""
}
return *bp.Uuid
}
func (bp *BalanceFilter) GetID() string {
if bp == nil || bp.ID == nil {
return ""
}
return *bp.ID
}
func (bp *BalanceFilter) GetDirections() utils.StringMap {
if bp == nil || bp.Directions == nil {
return utils.StringMap{}
}
return *bp.Directions
}
func (bp *BalanceFilter) GetDestinationIDs() utils.StringMap {
if bp == nil || bp.DestinationIDs == nil {
return utils.StringMap{}
}
return *bp.DestinationIDs
}
func (bp *BalanceFilter) GetCategories() utils.StringMap {
if bp == nil || bp.Categories == nil {
return utils.StringMap{}
}
return *bp.Categories
}
func (bp *BalanceFilter) GetTimingIDs() utils.StringMap {
if bp == nil || bp.TimingIDs == nil {
return utils.StringMap{}
}
return *bp.TimingIDs
}
func (bp *BalanceFilter) GetSharedGroups() utils.StringMap {
if bp == nil || bp.SharedGroups == nil {
return utils.StringMap{}
}
return *bp.SharedGroups
}
func (bp *BalanceFilter) GetWeight() float64 {
if bp == nil || bp.Weight == nil {
return 0.0
}
return *bp.Weight
}
func (bp *BalanceFilter) GetRatingSubject() string {
if bp == nil || bp.RatingSubject == nil {
return ""
}
return *bp.RatingSubject
}
func (bp *BalanceFilter) GetDisabled() bool {
if bp == nil || bp.Disabled == nil {
return false
}
return *bp.Disabled
}
func (bp *BalanceFilter) GetBlocker() bool {
if bp == nil || bp.Blocker == nil {
return false
}
return *bp.Blocker
}
func (bp *BalanceFilter) GetExpirationDate() time.Time {
if bp == nil || bp.ExpirationDate == nil {
return time.Time{}
}
return *bp.ExpirationDate
}
func (bp *BalanceFilter) GetFactor() ValueFactor {
if bp == nil || bp.Factor == nil {
return ValueFactor{}
}
return *bp.Factor
}
func (bp *BalanceFilter) HasExpirationDate() bool {
if bp.ExpirationDate == nil {
return true
}
return (*bp.ExpirationDate).IsZero()
}

View File

@@ -79,14 +79,14 @@ func (b *Balance) MatchFilter(o *BalanceFilter, skipIds bool) bool {
if !skipIds && o.Uuid != nil && *o.Uuid != "" {
return b.Uuid == *o.Uuid
}
if !skipIds && o.Id != nil && *o.Id != "" {
return b.Id == *o.Id
if !skipIds && o.ID != nil && *o.ID != "" {
return b.Id == *o.ID
}
return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) &&
(o.Weight == nil || b.Weight == *o.Weight) &&
(o.Blocker == nil || b.Blocker == *o.Blocker) &&
(o.Disabled == nil || b.Disabled == *o.Disabled) &&
(o.DestinationIds == nil || b.DestinationIds.Includes(*o.DestinationIds)) &&
(o.DestinationIDs == nil || b.DestinationIds.Includes(*o.DestinationIDs)) &&
(o.Directions == nil || b.Directions.Includes(*o.Directions)) &&
(o.Categories == nil || b.Categories.Includes(*o.Categories)) &&
(o.TimingIDs == nil || b.TimingIDs.Includes(*o.TimingIDs)) &&
@@ -101,14 +101,14 @@ func (b *Balance) HardMatchFilter(o *BalanceFilter, skipIds bool) bool {
if !skipIds && o.Uuid != nil && *o.Uuid != "" {
return b.Uuid == *o.Uuid
}
if !skipIds && o.Id != nil && *o.Id != "" {
return b.Id == *o.Id
if !skipIds && o.ID != nil && *o.ID != "" {
return b.Id == *o.ID
}
return (o.ExpirationDate == nil || b.ExpirationDate.Equal(*o.ExpirationDate)) &&
(o.Weight == nil || b.Weight == *o.Weight) &&
(o.Blocker == nil || b.Blocker == *o.Blocker) &&
(o.Disabled == nil || b.Disabled == *o.Disabled) &&
(o.DestinationIds == nil || b.DestinationIds.Equal(*o.DestinationIds)) &&
(o.DestinationIDs == nil || b.DestinationIds.Equal(*o.DestinationIDs)) &&
(o.Directions == nil || b.Directions.Equal(*o.Directions)) &&
(o.Categories == nil || b.Categories.Equal(*o.Categories)) &&
(o.TimingIDs == nil || b.TimingIDs.Equal(*o.TimingIDs)) &&
@@ -116,40 +116,6 @@ func (b *Balance) HardMatchFilter(o *BalanceFilter, skipIds bool) bool {
(o.RatingSubject == nil || b.RatingSubject == *o.RatingSubject)
}
func (b *Balance) MatchCCFilter(cc *CallCost) bool {
if len(b.Categories) > 0 && cc.Category != "" && b.Categories[cc.Category] == false {
return false
}
if len(b.Directions) > 0 && cc.Direction != "" && b.Directions[cc.Direction] == false {
return false
}
// match destination ids
foundMatchingDestId := false
if len(b.DestinationIds) > 0 && cc.Destination != "" {
for _, p := range utils.SplitPrefix(cc.Destination, MIN_PREFIX_MATCH) {
if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil {
destIds := x.(map[interface{}]struct{})
for filterDestId := range b.DestinationIds {
if _, ok := destIds[filterDestId]; ok {
foundMatchingDestId = true
break
}
}
}
if foundMatchingDestId {
break
}
}
} else {
foundMatchingDestId = true
}
if !foundMatchingDestId {
return false
}
return true
}
// the default balance has standard Id
func (b *Balance) IsDefault() bool {
return b.Id == utils.META_DEFAULT

View File

@@ -90,7 +90,7 @@ func TestBalanceEqual(t *testing.T) {
func TestBalanceMatchFilter(t *testing.T) {
mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}}
mb2 := &BalanceFilter{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIds: nil}
mb2 := &BalanceFilter{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIDs: nil}
if !mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
}
@@ -106,7 +106,7 @@ func TestBalanceMatchFilterEmpty(t *testing.T) {
func TestBalanceMatchFilterId(t *testing.T) {
mb1 := &Balance{Id: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIds: utils.NewStringMap("NAT")}
mb2 := &BalanceFilter{Id: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIds: nil}
mb2 := &BalanceFilter{ID: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
if !mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
}
@@ -114,7 +114,7 @@ func TestBalanceMatchFilterId(t *testing.T) {
func TestBalanceMatchFilterDiffId(t *testing.T) {
mb1 := &Balance{Id: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIds: utils.StringMap{}}
mb2 := &BalanceFilter{Id: utils.StringPointer("T2"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIds: nil}
mb2 := &BalanceFilter{ID: utils.StringPointer("T2"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
if mb1.MatchFilter(mb2, false) {
t.Errorf("Match filter failure: %+v != %+v", mb1, mb2)
}
@@ -129,7 +129,7 @@ func TestBalanceClone(t *testing.T) {
}
func TestBalanceMatchActionTriggerId(t *testing.T) {
at := &ActionTrigger{Balance: &BalanceFilter{Id: utils.StringPointer("test")}}
at := &ActionTrigger{Balance: &BalanceFilter{ID: utils.StringPointer("test")}}
b := &Balance{Id: "test"}
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
@@ -143,14 +143,14 @@ func TestBalanceMatchActionTriggerId(t *testing.T) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
b.Id = "test"
at.Balance.Id = nil
at.Balance.ID = nil
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
}
func TestBalanceMatchActionTriggerDestination(t *testing.T) {
at := &ActionTrigger{Balance: &BalanceFilter{DestinationIds: utils.StringMapPointer(utils.NewStringMap("test"))}}
at := &ActionTrigger{Balance: &BalanceFilter{DestinationIDs: utils.StringMapPointer(utils.NewStringMap("test"))}}
b := &Balance{DestinationIds: utils.NewStringMap("test")}
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
@@ -164,7 +164,7 @@ func TestBalanceMatchActionTriggerDestination(t *testing.T) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}
b.DestinationIds = utils.NewStringMap("test")
at.Balance.DestinationIds = nil
at.Balance.DestinationIDs = nil
if !b.MatchActionTrigger(at) {
t.Errorf("Error matching action trigger: %+v %+v", b, at)
}

View File

@@ -21,6 +21,7 @@ import (
"errors"
"time"
"github.com/cgrates/cgrates/cache2go"
"github.com/cgrates/cgrates/utils"
)
@@ -180,3 +181,40 @@ func (cc *CallCost) updateCost() {
}
cc.Cost = cost
}
func (cc *CallCost) MatchCCFilter(bf *BalanceFilter) bool {
if bf == nil {
return true
}
if bf.Categories != nil && cc.Category != "" && (*bf.Categories)[cc.Category] == false {
return false
}
if bf.Directions != nil && cc.Direction != "" && (*bf.Directions)[cc.Direction] == false {
return false
}
// match destination ids
foundMatchingDestID := false
if bf.DestinationIDs != nil && cc.Destination != "" {
for _, p := range utils.SplitPrefix(cc.Destination, MIN_PREFIX_MATCH) {
if x, err := cache2go.Get(utils.DESTINATION_PREFIX + p); err == nil {
destIds := x.(map[interface{}]struct{})
for filterDestID := range *bf.DestinationIDs {
if _, ok := destIds[filterDestID]; ok {
foundMatchingDestID = true
break
}
}
}
if foundMatchingDestID {
break
}
}
} else {
foundMatchingDestID = true
}
if !foundMatchingDestID {
return false
}
return true
}

View File

@@ -42,7 +42,7 @@ func init() {
func populateDB() {
ats := []*Action{
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: utils.Float64Pointer(10)}},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
&Action{ActionType: "*topup", Balance: &BalanceFilter{Type: utils.StringPointer(utils.VOICE), Weight: utils.Float64Pointer(20), Value: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}},
}
ats1 := []*Action{

View File

@@ -832,10 +832,12 @@ func TestLoadActions(t *testing.T) {
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
Value: utils.Float64Pointer(10),
Weight: utils.Float64Pointer(10),
DestinationIds: nil,
DestinationIDs: nil,
TimingIDs: nil,
SharedGroups: nil,
Categories: nil,
Disabled: utils.BoolPointer(false),
Blocker: utils.BoolPointer(false),
},
},
&Action{
@@ -851,10 +853,12 @@ func TestLoadActions(t *testing.T) {
Value: utils.Float64Pointer(100),
Weight: utils.Float64Pointer(10),
RatingSubject: utils.StringPointer("test"),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
TimingIDs: nil,
SharedGroups: nil,
Categories: nil,
Disabled: utils.BoolPointer(false),
Blocker: utils.BoolPointer(false),
},
},
}
@@ -871,13 +875,15 @@ func TestLoadActions(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: nil,
DestinationIDs: nil,
Uuid: as2[0].Balance.Uuid,
Value: utils.Float64Pointer(100),
Weight: utils.Float64Pointer(10),
SharedGroups: utils.StringMapPointer(utils.NewStringMap("SG1")),
TimingIDs: nil,
Categories: nil,
Disabled: utils.BoolPointer(false),
Blocker: utils.BoolPointer(false),
},
},
}
@@ -894,11 +900,12 @@ func TestLoadActions(t *testing.T) {
Balance: &BalanceFilter{
Uuid: as3[0].Balance.Uuid,
Directions: nil,
DestinationIds: nil,
DestinationIDs: nil,
TimingIDs: nil,
Categories: nil,
SharedGroups: nil,
Blocker: utils.BoolPointer(false),
Disabled: utils.BoolPointer(false),
},
},
}
@@ -1048,19 +1055,22 @@ func TestLoadActionTriggers(t *testing.T) {
ThresholdType: utils.TRIGGER_MIN_EVENT_COUNTER,
ThresholdValue: 10,
Balance: &BalanceFilter{
ID: utils.StringPointer("st0"),
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
Categories: nil,
TimingIDs: nil,
SharedGroups: nil,
Disabled: nil,
Blocker: nil,
},
Weight: 10,
ActionsId: "SOME_1",
Executed: false,
}
if !reflect.DeepEqual(atr, expected) {
t.Errorf("Error loading action trigger: %+v", atr)
t.Errorf("Error loading action trigger: %+v", utils.ToIJSON(atr.Balance))
}
atr = csvr.actionsTriggers["STANDARD_TRIGGER"][1]
expected = &ActionTrigger{
@@ -1071,7 +1081,7 @@ func TestLoadActionTriggers(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("GERMANY")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY")),
Categories: nil,
TimingIDs: nil,
SharedGroups: nil,
@@ -1093,18 +1103,22 @@ func TestLoadAccountActions(t *testing.T) {
expected := &Account{
Id: "vdf:minitsboy",
UnitCounters: UnitCounters{
&UnitCounter{
BalanceType: "*voice",
CounterType: "*event",
Balances: BalanceChain{
&Balance{
Id: "2c2ce3c9-d62b-49dc-82a5-2a17bdc6eb4e",
Value: 0,
Directions: utils.NewStringMap("*out"),
DestinationIds: utils.NewStringMap("GERMANY_O2"),
SharedGroups: nil,
Categories: nil,
TimingIDs: nil,
utils.VOICE: []*UnitCounter{
&UnitCounter{
CounterType: "*event",
Counters: CounterFilters{
&CounterFilter{
Value: 0,
Filter: &BalanceFilter{
ID: utils.StringPointer("st0"),
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap("*out")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("GERMANY_O2")),
SharedGroups: nil,
Categories: nil,
TimingIDs: nil,
},
},
},
},
},
@@ -1115,11 +1129,11 @@ func TestLoadAccountActions(t *testing.T) {
for i, atr := range aa.ActionTriggers {
csvr.actionsTriggers["STANDARD_TRIGGER"][i].ID = atr.ID
}
for i, b := range aa.UnitCounters[0].Balances {
expected.UnitCounters[0].Balances[i].Id = b.Id
for i, b := range aa.UnitCounters[utils.VOICE][0].Counters {
expected.UnitCounters[utils.VOICE][0].Counters[i].Filter.ID = b.Filter.ID
}
if !reflect.DeepEqual(aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0]) {
t.Errorf("Error loading account action: %+v \n %+v", aa.UnitCounters[0].Balances[0], expected.UnitCounters[0].Balances[0])
if !reflect.DeepEqual(aa.UnitCounters[utils.VOICE][0].Counters[0], expected.UnitCounters[utils.VOICE][0].Counters[0]) {
t.Errorf("Error loading account action: %+v", utils.ToIJSON(aa.UnitCounters[utils.VOICE][0].Counters[0].Filter))
}
// test that it does not overwrite balances
existing, err := accountingStorage.GetAccount(aa.Id)

View File

@@ -265,8 +265,8 @@ func TestTPActionsAsExportSlice(t *testing.T) {
},
}
expectedSlc := [][]string{
[]string{"TEST_ACTIONS", "*topup_reset", "", "", "", "*monetary", utils.OUT, "call", "*any", "special1", "GROUP1", "*never", "", "5", "10", "false", "false", "10"},
[]string{"TEST_ACTIONS", "*http_post", "http://localhost/&param1=value1", "", "", "", "", "", "", "", "", "", "", "0", "0", "false", "false", "20"},
[]string{"TEST_ACTIONS", "*topup_reset", "", "", "", "*monetary", utils.OUT, "call", "*any", "special1", "GROUP1", "*never", "", "5.0", "10.0", "", "", "10"},
[]string{"TEST_ACTIONS", "*http_post", "http://localhost/&param1=value1", "", "", "", "", "", "", "", "", "", "", "0.0", "0.0", "", "", "20"},
}
ms := APItoModelAction(tpActs)
@@ -597,8 +597,8 @@ func TestTPActionPlanAsExportSlice(t *testing.T) {
},
}
expectedSlc := [][]string{
[]string{"STANDARD_TRIGGERS", "1", "*min_balance", "2", "false", "0", "", "", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "T1", "0", "false", "false", "0", "LOG_WARNING", "10"},
[]string{"STANDARD_TRIGGERS", "2", "*max_event_counter", "5", "false", "0", "", "", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "T1", "0", "false", "false", "0", "LOG_WARNING", "10"},
[]string{"STANDARD_TRIGGERS", "1", "*min_balance", "2", "false", "0", "", "", "b1", "*monetary", "*out", "call", "", "special1", "SHARED_1", "*never", "T1", "0.0", "false", "false", "0", "LOG_WARNING", "10"},
[]string{"STANDARD_TRIGGERS", "2", "*max_event_counter", "5", "false", "0", "", "", "b2", "*monetary", "*out", "call", "FS_USERS", "special1", "SHARED_1", "*never", "T1", "0.0", "false", "false", "0", "LOG_WARNING", "10"},
}
ms := APItoModelActionTrigger(at)
var slc [][]string

View File

@@ -311,8 +311,7 @@ func TestStorageTask(t *testing.T) {
func GetUB() *Account {
uc := &UnitCounter{
BalanceType: utils.SMS,
Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
at := &ActionTrigger{
ID: "some_uuid",
@@ -320,7 +319,7 @@ func GetUB() *Account {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
},
Weight: 10.0,
ActionsId: "Commando",
@@ -331,7 +330,7 @@ func GetUB() *Account {
Id: "rif",
AllowNegative: true,
BalanceMap: map[string]BalanceChain{utils.SMS: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, utils.DATA: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, utils.VOICE: BalanceChain{&Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}}},
UnitCounters: UnitCounters{uc, uc},
UnitCounters: UnitCounters{utils.SMS: []*UnitCounter{uc, uc}},
ActionTriggers: ActionTriggers{at, at, at},
}
return ub

View File

@@ -524,7 +524,7 @@ func (tpr *TpReader) LoadActions() (err error) {
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -563,7 +563,7 @@ func (tpr *TpReader) LoadActions() (err error) {
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))
@@ -706,7 +706,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) {
MinQueuedItems: atr.MinQueuedItems,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -738,7 +738,7 @@ func (tpr *TpReader) LoadActionTriggers() (err error) {
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -906,7 +906,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
ActionsId: atr.ActionsId,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -938,7 +938,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -1006,7 +1006,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -1038,7 +1038,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))
@@ -1243,7 +1243,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
ActionsId: atr.ActionsId,
}
if atr.BalanceId != "" && atr.BalanceId != utils.ANY {
atrs[idx].Balance.Id = utils.StringPointer(atr.BalanceId)
atrs[idx].Balance.ID = utils.StringPointer(atr.BalanceId)
}
if atr.BalanceType != "" && atr.BalanceType != utils.ANY {
@@ -1275,7 +1275,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
atrs[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDirections))
}
if atr.BalanceDestinationIds != "" && atr.BalanceDestinationIds != utils.ANY {
atrs[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
atrs[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceDestinationIds))
}
if atr.BalanceSharedGroups != "" && atr.BalanceSharedGroups != utils.ANY {
atrs[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(atr.BalanceSharedGroups))
@@ -1352,7 +1352,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
Balance: &BalanceFilter{},
}
if tpact.BalanceId != "" && tpact.BalanceId != utils.ANY {
acts[idx].Balance.Id = utils.StringPointer(tpact.BalanceId)
acts[idx].Balance.ID = utils.StringPointer(tpact.BalanceId)
}
if tpact.BalanceType != "" && tpact.BalanceType != utils.ANY {
acts[idx].Balance.Type = utils.StringPointer(tpact.BalanceType)
@@ -1384,7 +1384,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
acts[idx].Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(tpact.Directions))
}
if tpact.DestinationIds != "" && tpact.DestinationIds != utils.ANY {
acts[idx].Balance.DestinationIds = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
acts[idx].Balance.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(tpact.DestinationIds))
}
if tpact.SharedGroups != "" && tpact.SharedGroups != utils.ANY {
acts[idx].Balance.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(tpact.SharedGroups))

View File

@@ -18,29 +18,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"log"
"github.com/cgrates/cgrates/utils"
)
import "github.com/cgrates/cgrates/utils"
// Amount of a trafic of a certain type
type UnitCounter struct {
BalanceType string // *monetary/*voice/*sms/etc
CounterType string // *event or *balance
Balances BalanceChain // first balance is the general one (no destination)
CounterType string // *event or *balance
Counters CounterFilters // first balance is the general one (no destination)
}
type CounterFilter struct {
Value float64
Filter *BalanceFilter
}
type CounterFilters []*CounterFilter
func (cfs CounterFilters) HasCounter(cf *CounterFilter) bool {
for _, c := range cfs {
if c.Filter.Equal(cf.Filter) {
return true
}
}
return false
}
// Returns true if the counters were of the same type
// Copies the value from old balances
func (uc *UnitCounter) CopyCounterValues(oldUc *UnitCounter) bool {
if uc.BalanceType+uc.CounterType != oldUc.BalanceType+oldUc.CounterType { // type check
if uc.CounterType != oldUc.CounterType { // type check
return false
}
for _, b := range uc.Balances {
for _, oldB := range oldUc.Balances {
if b.Equal(oldB) {
b.Value = oldB.Value
for _, c := range uc.Counters {
for _, oldC := range oldUc.Counters {
if c.Filter.Equal(oldC.Filter) {
c.Value = oldC.Value
break
}
}
@@ -48,30 +59,28 @@ func (uc *UnitCounter) CopyCounterValues(oldUc *UnitCounter) bool {
return true
}
type UnitCounters []*UnitCounter
type UnitCounters map[string][]*UnitCounter
func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *Balance) {
for _, uc := range ucs {
counters, found := ucs[kind]
if !found {
return
}
for _, uc := range counters {
if uc == nil { // safeguard
continue
}
if uc.BalanceType != kind {
continue
}
if uc.CounterType == "" {
uc.CounterType = utils.COUNTER_EVENT
}
for _, bal := range uc.Balances {
log.Print(b)
if uc.CounterType == utils.COUNTER_EVENT && cc != nil && bal.MatchCCFilter(cc) {
log.Print("HERE")
bal.AddValue(amount)
for _, c := range uc.Counters {
if uc.CounterType == utils.COUNTER_EVENT && cc != nil && cc.MatchCCFilter(c.Filter) {
c.Value += amount
continue
}
bp := &BalanceFilter{}
bp.LoadFromBalance(bal)
if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(bp, true) {
bal.AddValue(amount)
if uc.CounterType == utils.COUNTER_BALANCE && b != nil && b.MatchFilter(c.Filter, true) {
c.Value += amount
continue
}
}
@@ -80,16 +89,18 @@ func (ucs UnitCounters) addUnits(amount float64, kind string, cc *CallCost, b *B
}
func (ucs UnitCounters) resetCounters(a *Action) {
for _, uc := range ucs {
if uc == nil { // safeguard
for key, counters := range ucs {
if a != nil && a.Balance.Type != nil && a.Balance.GetType() != key {
continue
}
if a != nil && a.Balance.Type != nil && a.Balance.GetType() != uc.BalanceType {
continue
}
for _, b := range uc.Balances {
if a == nil || a.Balance == nil || b.MatchFilter(a.Balance, false) {
b.Value = 0
for _, c := range counters {
if c == nil { // safeguard
continue
}
for _, cf := range c.Counters {
if a == nil || a.Balance == nil || cf.Filter.Equal(a.Balance) {
cf.Value = 0
}
}
}
}

View File

@@ -26,22 +26,20 @@ import (
func TestUnitsCounterAddBalance(t *testing.T) {
uc := &UnitCounter{
BalanceType: utils.SMS,
Balances: BalanceChain{&Balance{Value: 1}, &Balance{Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
UnitCounters{uc}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
if len(uc.Balances) != 3 {
t.Error("Error adding minute bucket: ", uc.Balances)
UnitCounters{utils.SMS: []*UnitCounter{uc}}.addUnits(20, utils.SMS, &CallCost{Destination: "test"}, nil)
if len(uc.Counters) != 3 {
t.Error("Error adding minute bucket: ", uc.Counters)
}
}
func TestUnitsCounterAddBalanceExists(t *testing.T) {
uc := &UnitCounter{
BalanceType: utils.SMS,
Balances: BalanceChain{&Balance{Value: 1}, &Balance{Value: 10, Weight: 20, DestinationIds: utils.NewStringMap("NAT")}, &Balance{Weight: 10, DestinationIds: utils.NewStringMap("RET")}},
Counters: CounterFilters{&CounterFilter{Value: 1}, &CounterFilter{Value: 10, Filter: &BalanceFilter{Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}, &CounterFilter{Filter: &BalanceFilter{Weight: utils.Float64Pointer(10), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET"))}}},
}
UnitCounters{uc}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
if len(uc.Balances) != 3 || uc.Balances[1].GetValue() != 15 {
UnitCounters{utils.SMS: []*UnitCounter{uc}}.addUnits(5, utils.SMS, &CallCost{Destination: "0723"}, nil)
if len(uc.Counters) != 3 || uc.Counters[1].Value != 15 {
t.Error("Error adding minute bucket!")
}
}
@@ -108,14 +106,17 @@ func TestUnitCountersCountAllMonetary(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
a.UnitCounters[0].Balances[0].Value != 10 ||
a.UnitCounters[0].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
@@ -183,15 +184,17 @@ func TestUnitCountersCountAllMonetaryId(t *testing.T) {
}
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, nil, &Balance{Weight: 20, Directions: utils.NewStringMap(utils.OUT)})
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
a.UnitCounters[0].Balances[0].Value != 0 ||
a.UnitCounters[0].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 0 ||
a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
@@ -225,7 +228,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
Weight: utils.Float64Pointer(10),
},
},
@@ -234,7 +237,7 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
Weight: utils.Float64Pointer(10),
},
},
@@ -270,14 +273,17 @@ func TestUnitCountersCountAllVoiceDestinationEvent(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[1].Balances) != 2 ||
a.UnitCounters[1].Balances[0].Value != 10 ||
a.UnitCounters[1].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
@@ -311,7 +317,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("NAT")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
Weight: utils.Float64Pointer(10),
},
},
@@ -320,7 +326,7 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER,
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.VOICE),
DestinationIds: utils.StringMapPointer(utils.NewStringMap("RET")),
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
Weight: utils.Float64Pointer(10),
},
},
@@ -356,28 +362,34 @@ func TestUnitCountersKeepValuesAfterInit(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.VOICE, &CallCost{Destination: "0723045326"}, nil)
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[1].Balances) != 2 ||
a.UnitCounters[1].Balances[0].Value != 10 ||
a.UnitCounters[1].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error adding unit counters: %v", len(a.UnitCounters))
}
a.InitCounters()
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[1].Balances) != 2 ||
a.UnitCounters[1].Balances[0].Value != 10 ||
a.UnitCounters[1].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.VOICE][0].Counters) != 2 ||
a.UnitCounters[utils.VOICE][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.VOICE][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error keeping counter values after init: %v", len(a.UnitCounters))
@@ -446,14 +458,17 @@ func TestUnitCountersResetCounterById(t *testing.T) {
a.InitCounters()
a.UnitCounters.addUnits(10, utils.MONETARY, &CallCost{}, nil)
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
a.UnitCounters[0].Balances[0].Value != 10 ||
a.UnitCounters[0].Balances[1].Value != 10 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 10 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))
@@ -461,17 +476,20 @@ func TestUnitCountersResetCounterById(t *testing.T) {
a.UnitCounters.resetCounters(&Action{
Balance: &BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Id: utils.StringPointer("TestTR11"),
ID: utils.StringPointer("TestTR11"),
},
})
if len(a.UnitCounters) != 4 ||
len(a.UnitCounters[0].Balances) != 2 ||
a.UnitCounters[0].Balances[0].Value != 10 ||
a.UnitCounters[0].Balances[1].Value != 0 {
for _, uc := range a.UnitCounters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Balances {
t.Logf("B: %+v", b)
if len(a.UnitCounters) != 3 ||
len(a.UnitCounters[utils.MONETARY][0].Counters) != 2 ||
a.UnitCounters[utils.MONETARY][0].Counters[0].Value != 10 ||
a.UnitCounters[utils.MONETARY][0].Counters[1].Value != 0 {
for key, counters := range a.UnitCounters {
t.Log(key)
for _, uc := range counters {
t.Logf("UC: %+v", uc)
for _, b := range uc.Counters {
t.Logf("B: %+v", b)
}
}
}
t.Errorf("Error Initializing adding unit counters: %v", len(a.UnitCounters))