mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
2919 lines
83 KiB
Go
2919 lines
83 KiB
Go
/*
|
|
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
|
Copyright (C) ITsysCOM GmbH
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*/
|
|
package engine
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cgrates/birpc"
|
|
"github.com/cgrates/birpc/context"
|
|
"github.com/cgrates/cgrates/config"
|
|
"github.com/cgrates/cgrates/utils"
|
|
"github.com/cgrates/rpcclient"
|
|
)
|
|
|
|
var (
|
|
err error
|
|
//referenceDate = time.Date(2013, 7, 10, 10, 30, 0, 0, time.Local)
|
|
//referenceDate = time.Date(2013, 12, 31, 23, 59, 59, 0, time.Local)
|
|
//referenceDate = time.Date(2011, 1, 1, 0, 0, 0, 1, time.Local)
|
|
referenceDate = time.Now()
|
|
now = referenceDate
|
|
)
|
|
|
|
func TestActionTimingAlways(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
y, m, d := referenceDate.Date()
|
|
expected := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanNothing(t *testing.T) {
|
|
at := &ActionTiming{}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionTimingMidnight(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}}
|
|
y, m, d := referenceDate.Date()
|
|
now := time.Date(y, m, d, 0, 0, 1, 0, time.Local)
|
|
st := at.GetNextStartTime(now)
|
|
expected := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanOnlyHour(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
|
|
y, m, d := now.Date()
|
|
expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
if referenceDate.After(expected) {
|
|
expected = expected.AddDate(0, 0, 1)
|
|
}
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourYear(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2024}, StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(2024, 1, 1, 10, 1, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanOnlyWeekdays(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
|
|
y, m, d := now.Date()
|
|
h, min, s := now.Clock()
|
|
e := time.Date(y, m, d, h, min, s, 0, time.Local)
|
|
day := e.Day()
|
|
e = time.Date(e.Year(), e.Month(), day, 0, 0, 0, 0, e.Location())
|
|
for i := 0; i < 8; i++ {
|
|
n := e.AddDate(0, 0, i)
|
|
if n.Weekday() == time.Monday && (n.Equal(now) || n.After(now)) {
|
|
e = n
|
|
break
|
|
}
|
|
}
|
|
if !st.Equal(e) {
|
|
t.Errorf("Expected %v was %v", e, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourWeekdays(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{
|
|
WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
|
|
y, m, d := now.Date()
|
|
e := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
day := e.Day()
|
|
for i := 0; i < 8; i++ {
|
|
e = time.Date(e.Year(), e.Month(), day, e.Hour(),
|
|
e.Minute(), e.Second(), e.Nanosecond(), e.Location())
|
|
n := e.AddDate(0, 0, i)
|
|
if n.Weekday() == time.Monday && (n.Equal(now) || n.After(now)) {
|
|
e = n
|
|
break
|
|
}
|
|
}
|
|
if !st.Equal(e) {
|
|
t.Errorf("Expected %v was %v", e, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanOnlyMonthdays(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := tomorrow
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourMonthdays(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
if now.After(testTime) {
|
|
y, m, d = tomorrow.Date()
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanOnlyMonths(t *testing.T) {
|
|
|
|
y, m, _ := now.Date()
|
|
nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0)
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(nextMonth.Year(), nextMonth.Month(), 1, 0, 0, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Log("NextMonth: ", nextMonth)
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourMonths(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0)
|
|
if now.After(testTime) {
|
|
testTime = testTime.AddDate(0, 0, 1)
|
|
y, m, d = testTime.Date()
|
|
}
|
|
if now.After(testTime) {
|
|
m = nextMonth.Month()
|
|
y = nextMonth.Year()
|
|
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{
|
|
Months: utils.Months{now.Month(), nextMonth.Month()},
|
|
StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(y, m, 1, 10, 1, 0, 0, time.Local)
|
|
if referenceDate.After(expected) {
|
|
expected = expected.AddDate(0, 1, 0)
|
|
}
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourMonthdaysMonths(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0)
|
|
tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
|
|
if now.After(testTime) {
|
|
y, m, d = tomorrow.Date()
|
|
}
|
|
nextDay := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
month := nextDay.Month()
|
|
if nextDay.Before(now) {
|
|
if now.After(testTime) {
|
|
month = nextMonth.Month()
|
|
}
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: utils.Months{now.Month(), nextMonth.Month()},
|
|
MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()},
|
|
StartTime: "10:01:00",
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(y, month, d, 10, 1, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanFirstOfTheMonth(t *testing.T) {
|
|
|
|
y, m, _ := now.Date()
|
|
nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0)
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
MonthDays: utils.MonthDays{1},
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := nextMonth
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanOnlyYears(t *testing.T) {
|
|
y, _, _ := referenceDate.Date()
|
|
nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0)
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := nextYear
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanPast(t *testing.T) {
|
|
at := &ActionTiming{
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{2028},
|
|
}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(2028, 1, 1, 0, 0, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourYears(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{
|
|
Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(referenceDate.Year(), 1, 1, 10, 1, 0, 0, time.Local)
|
|
if referenceDate.After(expected) {
|
|
expected = expected.AddDate(1, 0, 0)
|
|
}
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourMonthdaysYear(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
tomorrow := time.Date(y, m, d, 10, 1, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
nextYear := time.Date(y, 1, d, 10, 1, 0, 0, time.Local).AddDate(1, 0, 0)
|
|
expected := testTime
|
|
if referenceDate.After(testTime) {
|
|
if referenceDate.After(tomorrow) {
|
|
expected = nextYear
|
|
} else {
|
|
expected = tomorrow
|
|
}
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{now.Year(), nextYear.Year()},
|
|
MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()},
|
|
StartTime: "10:01:00",
|
|
},
|
|
}}
|
|
t.Log(at.Timing.Timing.CronString())
|
|
t.Log(time.Now(), referenceDate, referenceDate.After(testTime), referenceDate.After(testTime))
|
|
st := at.GetNextStartTime(referenceDate)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanHourMonthdaysMonthYear(t *testing.T) {
|
|
|
|
y, m, d := now.Date()
|
|
testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local)
|
|
nextYear := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0)
|
|
nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0)
|
|
tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1)
|
|
day := now.Day()
|
|
if now.After(testTime) {
|
|
day = tomorrow.Day()
|
|
}
|
|
nextDay := time.Date(y, m, day, 10, 1, 0, 0, time.Local)
|
|
month := now.Month()
|
|
if nextDay.Before(now) {
|
|
if now.After(testTime) {
|
|
month = nextMonth.Month()
|
|
}
|
|
}
|
|
nextDay = time.Date(y, month, day, 10, 1, 0, 0, time.Local)
|
|
year := now.Year()
|
|
if nextDay.Before(now) {
|
|
if now.After(testTime) {
|
|
year = nextYear.Year()
|
|
}
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{now.Year(), nextYear.Year()},
|
|
Months: utils.Months{now.Month(), nextMonth.Month()},
|
|
MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()},
|
|
StartTime: "10:01:00",
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := time.Date(year, month, day, 10, 1, 0, 0, time.Local)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanFirstOfTheYear(t *testing.T) {
|
|
y, _, _ := now.Date()
|
|
nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0)
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{nextYear.Year()},
|
|
Months: utils.Months{time.January},
|
|
MonthDays: utils.MonthDays{1},
|
|
StartTime: "00:00:00",
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
expected := nextYear
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanFirstMonthOfTheYear(t *testing.T) {
|
|
y, _, _ := now.Date()
|
|
expected := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local)
|
|
if referenceDate.After(expected) {
|
|
expected = expected.AddDate(1, 0, 0)
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: utils.Months{time.January},
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanFirstMonthOfTheYearSecondDay(t *testing.T) {
|
|
y, _, _ := now.Date()
|
|
expected := time.Date(y, 1, 2, 0, 0, 0, 0, time.Local)
|
|
if referenceDate.After(expected) {
|
|
expected = expected.AddDate(1, 0, 0)
|
|
}
|
|
at := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: utils.Months{time.January},
|
|
MonthDays: utils.MonthDays{2},
|
|
},
|
|
}}
|
|
st := at.GetNextStartTime(referenceDate)
|
|
if !st.Equal(expected) {
|
|
t.Errorf("Expected %v was %v", expected, st)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanCheckForASAP(t *testing.T) {
|
|
at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: utils.ASAP}}}
|
|
if !at.IsASAP() {
|
|
t.Errorf("%v should be asap!", at)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanLogFunction(t *testing.T) {
|
|
a := &Action{
|
|
ActionType: "*log",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer("test"),
|
|
Value: &utils.ValueFormula{Static: 1.1},
|
|
},
|
|
}
|
|
at := &ActionTiming{
|
|
actions: []*Action{a},
|
|
}
|
|
err := at.Execute(nil, nil)
|
|
if err != nil {
|
|
t.Errorf("Could not execute LOG action: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestActionPlanFunctionNotAvailable(t *testing.T) {
|
|
a := &Action{
|
|
ActionType: "VALID_FUNCTION_TYPE",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer("test"),
|
|
Value: &utils.ValueFormula{Static: 1.1},
|
|
},
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:dy": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{a},
|
|
}
|
|
err := at.Execute(nil, nil)
|
|
if err != utils.ErrPartiallyExecuted { // because we want to return err if we can't execute all actions
|
|
t.Errorf("Faild to detect wrong function type: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestActionTimingPriorityListSortByWeight(t *testing.T) {
|
|
at1 := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{2040},
|
|
Months: utils.Months{time.January, time.February, time.March,
|
|
time.April, time.May, time.June, time.July, time.August, time.September,
|
|
time.October, time.November, time.December},
|
|
MonthDays: utils.MonthDays{1},
|
|
StartTime: "00:00:00",
|
|
},
|
|
Weight: 20,
|
|
}}
|
|
at2 := &ActionTiming{Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{2040},
|
|
Months: utils.Months{time.January, time.February, time.March,
|
|
time.April, time.May, time.June, time.July, time.August, time.September,
|
|
time.October, time.November, time.December},
|
|
MonthDays: utils.MonthDays{2},
|
|
StartTime: "00:00:00",
|
|
},
|
|
Weight: 10,
|
|
}}
|
|
var atpl ActionTimingPriorityList
|
|
atpl = append(atpl, at2, at1)
|
|
atpl.Sort()
|
|
if atpl[0] != at1 || atpl[1] != at2 {
|
|
t.Error("Timing list not sorted correctly: ", at1, at2, atpl)
|
|
}
|
|
}
|
|
|
|
func TestActionTimingPriorityListWeight(t *testing.T) {
|
|
at1 := &ActionTiming{
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: utils.Months{time.January, time.February, time.March,
|
|
time.April, time.May, time.June, time.July, time.August, time.September,
|
|
time.October, time.November, time.December},
|
|
MonthDays: utils.MonthDays{1},
|
|
StartTime: "00:00:00",
|
|
},
|
|
},
|
|
Weight: 20,
|
|
}
|
|
at2 := &ActionTiming{
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Months: utils.Months{time.January, time.February, time.March,
|
|
time.April, time.May, time.June, time.July, time.August, time.September,
|
|
time.October, time.November, time.December},
|
|
MonthDays: utils.MonthDays{1},
|
|
StartTime: "00:00:00",
|
|
},
|
|
},
|
|
Weight: 10,
|
|
}
|
|
var atpl ActionTimingPriorityList
|
|
atpl = append(atpl, at2, at1)
|
|
atpl.Sort()
|
|
if atpl[0] != at1 || atpl[1] != at2 {
|
|
t.Error("Timing list not sorted correctly: ", atpl)
|
|
}
|
|
}
|
|
|
|
func TestActionPlansRemoveMember(t *testing.T) {
|
|
|
|
account1 := &Account{ID: "one"}
|
|
account2 := &Account{ID: "two"}
|
|
|
|
dm.SetAccount(account1)
|
|
dm.SetAccount(account2)
|
|
|
|
ap1 := &ActionPlan{
|
|
Id: "TestActionPlansRemoveMember1",
|
|
AccountIDs: utils.StringMap{"one": true},
|
|
ActionTimings: []*ActionTiming{
|
|
{
|
|
Uuid: "uuid1",
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{2012},
|
|
Months: utils.Months{},
|
|
MonthDays: utils.MonthDays{},
|
|
WeekDays: utils.WeekDays{},
|
|
StartTime: utils.ASAP,
|
|
},
|
|
},
|
|
Weight: 10,
|
|
ActionsID: "MINI",
|
|
},
|
|
},
|
|
}
|
|
|
|
ap2 := &ActionPlan{
|
|
Id: "test2",
|
|
AccountIDs: utils.StringMap{"two": true},
|
|
ActionTimings: []*ActionTiming{
|
|
{
|
|
Uuid: "uuid2",
|
|
Timing: &RateInterval{
|
|
Timing: &RITiming{
|
|
Years: utils.Years{2012},
|
|
Months: utils.Months{},
|
|
MonthDays: utils.MonthDays{},
|
|
WeekDays: utils.WeekDays{},
|
|
StartTime: utils.ASAP,
|
|
},
|
|
},
|
|
Weight: 10,
|
|
ActionsID: "MINI",
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetActionPlan(ap1.Id, ap1, true,
|
|
utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = dm.SetActionPlan(ap2.Id, ap2, true,
|
|
utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = dm.CacheDataFromDB(utils.ACTION_PLAN_PREFIX,
|
|
[]string{ap1.Id, ap2.Id}, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = dm.SetAccountActionPlans(account1.ID,
|
|
[]string{ap1.Id}, false); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix,
|
|
[]string{account1.ID}, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm.GetAccountActionPlans(account1.ID, false, true, utils.NonTransactional) // FixMe: remove here after finishing testing of map
|
|
if err = dm.SetAccountActionPlans(account2.ID,
|
|
[]string{ap2.Id}, false); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = dm.CacheDataFromDB(utils.AccountActionPlansPrefix,
|
|
[]string{account2.ID}, false); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
actions := []*Action{
|
|
{
|
|
Id: "REMOVE",
|
|
ActionType: utils.REMOVE_ACCOUNT,
|
|
},
|
|
}
|
|
|
|
dm.SetActions(actions[0].Id, actions, utils.NonTransactional)
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{account1.ID: true},
|
|
Timing: &RateInterval{},
|
|
actions: actions,
|
|
}
|
|
|
|
if err = at.Execute(nil, nil); err != nil {
|
|
t.Errorf("Execute Action: %v", err)
|
|
}
|
|
|
|
apr, err1 := dm.GetActionPlan(ap1.Id, true, true, utils.NonTransactional)
|
|
|
|
if err1 != nil {
|
|
t.Errorf("Get action plan test: %v", err1)
|
|
}
|
|
|
|
if _, exist := apr.AccountIDs[account1.ID]; exist {
|
|
t.Errorf("Account one is not deleted ")
|
|
}
|
|
|
|
}
|
|
|
|
func TestActionTriggerMatchNil(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
var a *Action
|
|
if !at.Match(a) {
|
|
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchAllBlank(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
a := &Action{}
|
|
if !at.Match(a) {
|
|
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchMinuteBucketBlank(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)},
|
|
ExtraParameters: `{"BalanceDirections":"*out"}`}
|
|
if !at.Match(a) {
|
|
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchMinuteBucketFull(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
a := &Action{ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v}`,
|
|
utils.TRIGGER_MAX_BALANCE, 2)}
|
|
if !at.Match(a) {
|
|
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchAllFull(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)},
|
|
ExtraParameters: fmt.Sprintf(`{"ThresholdType":"%v", "ThresholdValue": %v}`,
|
|
utils.TRIGGER_MAX_BALANCE, 2)}
|
|
if !at.Match(a) {
|
|
t.Errorf("Action trigger [%v] does not match action [%v]", at, a)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchSomeFalse(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 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)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatcBalanceFalse(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)},
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatcAllFalse(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
|
ThresholdValue: 2,
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggerMatchAll(t *testing.T) {
|
|
at := &ActionTrigger{
|
|
ID: "TEST",
|
|
UniqueID: "ZIP",
|
|
ThresholdType: "TT",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
RatingSubject: utils.StringPointer("test1"),
|
|
Value: &utils.ValueFormula{Static: 2},
|
|
Weight: utils.Float64Pointer(1.0),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")),
|
|
SharedGroups: utils.StringMapPointer(utils.NewStringMap("test2")),
|
|
},
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
RatingSubject: utils.StringPointer("test1"),
|
|
Value: &utils.ValueFormula{Static: 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)
|
|
}
|
|
}
|
|
|
|
func TestActionTriggers(t *testing.T) {
|
|
at1 := &ActionTrigger{Weight: 30}
|
|
at2 := &ActionTrigger{Weight: 20}
|
|
at3 := &ActionTrigger{Weight: 10}
|
|
var atpl ActionTriggers
|
|
atpl = append(atpl, at2, at1, at3)
|
|
atpl.Sort()
|
|
if atpl[0] != at1 || atpl[2] != at3 || atpl[1] != at2 {
|
|
t.Error("List not sorted: ", atpl)
|
|
}
|
|
}
|
|
|
|
func TestActionResetTriggres(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 10},
|
|
},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")},
|
|
},
|
|
},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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)
|
|
if ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
|
|
t.Error("Reset triggers action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionResetTriggresExecutesThem(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 10},
|
|
},
|
|
},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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)
|
|
if ub.ActionTriggers[0].Executed == true || ub.BalanceMap[utils.MONETARY][0].GetValue() == 12 {
|
|
t.Error("Reset triggers action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionResetTriggresActionFilter(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 10},
|
|
},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")},
|
|
},
|
|
},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.SMS)}}, nil, nil)
|
|
if ub.ActionTriggers[0].Executed == false || ub.ActionTriggers[1].Executed == false {
|
|
t.Error("Reset triggers action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionResetTriggresActionFilter2(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TestActionResetTriggresActionFilter2",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 10},
|
|
},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")},
|
|
},
|
|
},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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, &Action{}, nil, nil)
|
|
if ub.ActionTriggers[0].Executed != false && ub.ActionTriggers[1].Executed != false {
|
|
t.Error("Reset triggers action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionSetPostpaid(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{utils.MONETARY: []*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)
|
|
if !ub.AllowNegative {
|
|
t.Error("Set postpaid action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionSetPrepaid(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
AllowNegative: true,
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{utils.MONETARY: []*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)
|
|
if ub.AllowNegative {
|
|
t.Error("Set prepaid action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionResetPrepaid(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
AllowNegative: true,
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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)
|
|
if !ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 0 ||
|
|
len(ub.UnitCounters) != 0 ||
|
|
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
|
|
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
|
|
t.Log(ub.BalanceMap)
|
|
t.Error("Reset account action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionResetPostpaid(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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)
|
|
if ub.BalanceMap[utils.MONETARY].GetTotalValue() != 0 ||
|
|
len(ub.UnitCounters) != 0 ||
|
|
ub.BalanceMap[utils.VOICE][0].GetValue() != 0 ||
|
|
ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true {
|
|
t.Error("Reset account action failed!")
|
|
}
|
|
}
|
|
|
|
func TestActionTopupResetCredit(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10}}}
|
|
topupResetAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 10 ||
|
|
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: %+s", utils.ToIJSON(ub))
|
|
}
|
|
}
|
|
|
|
func TestActionTopupValueFactor(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{},
|
|
}
|
|
a := &Action{
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10},
|
|
},
|
|
ExtraParameters: `{"*monetary":2.0}`,
|
|
}
|
|
topupResetAction(ub, a, nil, nil)
|
|
if len(ub.BalanceMap) != 1 ||
|
|
ub.BalanceMap[utils.MONETARY][0].Factor[utils.MONETARY] != 2.0 {
|
|
t.Errorf("Topup reset action failed to set Factor: %+v",
|
|
ub.BalanceMap[utils.MONETARY][0].Factor)
|
|
}
|
|
}
|
|
|
|
func TestActionTopupResetCreditId(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 100},
|
|
&Balance{ID: "TEST_B", Value: 15},
|
|
},
|
|
},
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
ID: utils.StringPointer("TEST_B"),
|
|
Value: &utils.ValueFormula{Static: 10}}}
|
|
topupResetAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
|
|
len(ub.BalanceMap[utils.MONETARY]) != 2 {
|
|
t.Errorf("Topup reset action failed: %+v",
|
|
ub.BalanceMap[utils.MONETARY][0])
|
|
}
|
|
}
|
|
|
|
func TestActionTopupResetCreditNoId(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 100},
|
|
&Balance{ID: "TEST_B", Value: 15},
|
|
},
|
|
},
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10}}}
|
|
topupResetAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 20 ||
|
|
len(ub.BalanceMap[utils.MONETARY]) != 2 {
|
|
t.Errorf("Topup reset action failed: %+v", ub.BalanceMap[utils.MONETARY][1])
|
|
}
|
|
}
|
|
|
|
func TestActionTopupResetMinutes(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{utils.MONETARY: []*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.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}
|
|
topupResetAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.VOICE].GetTotalValue() != 5 ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
|
|
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])
|
|
}
|
|
}
|
|
|
|
func TestActionTopupCredit(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10,
|
|
DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10}}}
|
|
topupAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 110 ||
|
|
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())
|
|
}
|
|
}
|
|
|
|
func TestActionTopupMinutes(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{Value: 100}},
|
|
utils.VOICE: {&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}
|
|
topupAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.VOICE].GetTotalValue() != 15 ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
|
|
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])
|
|
}
|
|
}
|
|
|
|
func TestActionDebitCredit(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10}}}
|
|
debitAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 90 ||
|
|
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!", utils.ToIJSON(ub))
|
|
}
|
|
}
|
|
|
|
func TestActionDebitMinutes(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*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.ValueFormula{Static: 5},
|
|
Weight: utils.Float64Pointer(20),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}}
|
|
debitAction(ub, a, nil, nil)
|
|
if ub.AllowNegative ||
|
|
ub.BalanceMap[utils.VOICE][0].GetValue() != 5 ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
|
|
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])
|
|
}
|
|
}
|
|
|
|
func TestActionResetAllCounters(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
AllowNegative: true,
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {
|
|
&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
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[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[utils.MONETARY][0], ub.UnitCounters[utils.MONETARY][0].Counters[0])
|
|
}
|
|
if len(ub.UnitCounters) < 1 {
|
|
t.FailNow()
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestActionResetCounterOnlyDefault(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
AllowNegative: true,
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {&Balance{Value: 10, Weight: 20,
|
|
DestinationIDs: utils.NewStringMap("NAT")}, &Balance{Weight: 10,
|
|
DestinationIDs: utils.NewStringMap("RET")}}},
|
|
ActionTriggers: ActionTriggers{
|
|
&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)},
|
|
ThresholdType: utils.TRIGGER_MAX_EVENT_COUNTER, ThresholdValue: 2,
|
|
ActionsID: "TEST_ACTIONS", Executed: true}},
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}}
|
|
ub.InitCounters()
|
|
resetCountersAction(ub, a, nil, nil)
|
|
if !ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
|
|
len(ub.UnitCounters) != 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[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[utils.MONETARY][0].Counters) < 1 {
|
|
t.FailNow()
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestActionResetCounterCredit(t *testing.T) {
|
|
ub := &Account{
|
|
ID: "TEST_UB",
|
|
AllowNegative: true,
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{Value: 100}},
|
|
utils.VOICE: {&Balance{Value: 10, Weight: 20, DestinationIDs: utils.NewStringMap("NAT")},
|
|
&Balance{Weight: 10, DestinationIDs: utils.NewStringMap("RET")}}},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*UnitCounter{
|
|
{Counters: CounterFilters{
|
|
&CounterFilter{Value: 1, Filter: new(BalanceFilter)}}}},
|
|
utils.SMS: []*UnitCounter{
|
|
{Counters: CounterFilters{
|
|
&CounterFilter{Value: 1, Filter: new(BalanceFilter)}}}}},
|
|
ActionTriggers: ActionTriggers{
|
|
&ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)},
|
|
ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}},
|
|
}
|
|
a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY)}}
|
|
resetCountersAction(ub, a, nil, nil)
|
|
if !ub.AllowNegative ||
|
|
ub.BalanceMap[utils.MONETARY].GetTotalValue() != 100 ||
|
|
len(ub.UnitCounters) != 2 ||
|
|
len(ub.BalanceMap[utils.VOICE]) != 2 ||
|
|
ub.ActionTriggers[0].Executed != true {
|
|
t.Error("Reset counters action failed!", ub.UnitCounters)
|
|
}
|
|
}
|
|
|
|
func TestActionMakeNegative(t *testing.T) {
|
|
a := &Action{Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 10}}}
|
|
genericMakeNegative(a)
|
|
if a.Balance.GetValue() > 0 {
|
|
t.Error("Failed to make negative: ", a)
|
|
}
|
|
genericMakeNegative(a)
|
|
if a.Balance.GetValue() > 0 {
|
|
t.Error("Failed to preserve negative: ", a)
|
|
}
|
|
}
|
|
|
|
func TestRemoveAction(t *testing.T) {
|
|
if _, err := dm.GetAccount("cgrates.org:remo"); err != nil {
|
|
t.Errorf("account to be removed not found: %v", err)
|
|
}
|
|
a := &Action{
|
|
ActionType: utils.REMOVE_ACCOUNT,
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:remo": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
afterUb, err := dm.GetAccount("cgrates.org:remo")
|
|
if err == nil || afterUb != nil {
|
|
t.Error("error removing account: ", err, afterUb)
|
|
}
|
|
}
|
|
|
|
func TestTopupAction(t *testing.T) {
|
|
initialUb, _ := dm.GetAccount("vdf:minu")
|
|
a := &Action{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY), Value: &utils.ValueFormula{Static: 25},
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
|
|
Weight: utils.Float64Pointer(20)},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"vdf:minu": true},
|
|
actions: Actions{a},
|
|
}
|
|
|
|
at.Execute(nil, nil)
|
|
afterUb, _ := dm.GetAccount("vdf:minu")
|
|
initialValue := initialUb.BalanceMap[utils.MONETARY].GetTotalValue()
|
|
afterValue := afterUb.BalanceMap[utils.MONETARY].GetTotalValue()
|
|
if afterValue != initialValue+25 {
|
|
t.Error("Bad topup before and after: ", initialValue, afterValue)
|
|
}
|
|
}
|
|
|
|
func TestTopupActionLoaded(t *testing.T) {
|
|
initialUb, _ := dm.GetAccount("vdf:minitsboy")
|
|
a := &Action{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 25},
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
|
|
Weight: utils.Float64Pointer(20)},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"vdf:minitsboy": true},
|
|
actions: Actions{a},
|
|
}
|
|
|
|
at.Execute(nil, nil)
|
|
afterUb, _ := dm.GetAccount("vdf:minitsboy")
|
|
initialValue := initialUb.BalanceMap[utils.MONETARY].GetTotalValue()
|
|
afterValue := afterUb.BalanceMap[utils.MONETARY].GetTotalValue()
|
|
if afterValue != initialValue+25 {
|
|
t.Logf("Initial: %+v", initialUb)
|
|
t.Logf("After: %+v", afterUb)
|
|
t.Error("Bad topup before and after: ", initialValue, afterValue)
|
|
}
|
|
}
|
|
|
|
func TestActionTransactionFuncType(t *testing.T) {
|
|
err := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:trans",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&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{
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1},
|
|
Type: utils.StringPointer(utils.MONETARY)},
|
|
},
|
|
{
|
|
ActionType: "VALID_FUNCTION_TYPE",
|
|
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1},
|
|
Type: utils.StringPointer("test")},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:trans")
|
|
if err != nil || acc == nil {
|
|
t.Error("Error getting account: ", acc, err)
|
|
}
|
|
if acc.BalanceMap[utils.MONETARY][0].Value != 10 {
|
|
t.Errorf("Transaction didn't work: %v", acc.BalanceMap[utils.MONETARY][0].Value)
|
|
}
|
|
}
|
|
|
|
func TestActionTransactionBalanceType(t *testing.T) {
|
|
err := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:trans",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&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{
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1},
|
|
Type: utils.StringPointer(utils.MONETARY)},
|
|
},
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Type: utils.StringPointer("test")},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:trans")
|
|
if err != nil || acc == nil {
|
|
t.Error("Error getting account: ", acc, err)
|
|
}
|
|
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 := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:trans",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&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{
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Value: &utils.ValueFormula{Static: 1.1},
|
|
Type: utils.StringPointer(utils.VOICE)},
|
|
},
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{Type: utils.StringPointer("test")},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.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)
|
|
}
|
|
}
|
|
|
|
func TestActionWithExpireWithoutExpire(t *testing.T) {
|
|
err := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:exp",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {&Balance{
|
|
Value: 10,
|
|
}},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Error("Error setting account: ", err)
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:exp": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.VOICE),
|
|
Value: &utils.ValueFormula{Static: 15},
|
|
},
|
|
},
|
|
{
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.VOICE),
|
|
Value: &utils.ValueFormula{Static: 30},
|
|
ExpirationDate: utils.TimePointer(time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:exp")
|
|
if err != nil || acc == nil {
|
|
t.Errorf("Error getting account: %+v: %v", acc, err)
|
|
}
|
|
if len(acc.BalanceMap) != 2 ||
|
|
len(acc.BalanceMap[utils.VOICE]) != 2 {
|
|
t.Errorf("Error debiting expir and unexpire: %+v", acc.BalanceMap[utils.VOICE][0])
|
|
}
|
|
}
|
|
|
|
func TestActionRemoveBalance(t *testing.T) {
|
|
err := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:rembal",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Value: 10,
|
|
},
|
|
&Balance{
|
|
Value: 10,
|
|
DestinationIDs: utils.NewStringMap("NAT", "RET"),
|
|
ExpirationDate: time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC),
|
|
},
|
|
&Balance{
|
|
Value: 10,
|
|
DestinationIDs: utils.NewStringMap("NAT", "RET"),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Error("Error setting account: ", err)
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:rembal": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{
|
|
{
|
|
ActionType: utils.REMOVE_BALANCE,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT", "RET")),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:rembal")
|
|
if err != nil || acc == nil {
|
|
t.Errorf("Error getting account: %+v: %v", acc, err)
|
|
}
|
|
if len(acc.BalanceMap) != 1 ||
|
|
len(acc.BalanceMap[utils.MONETARY]) != 1 {
|
|
t.Errorf("Error removing balance: %+v", acc.BalanceMap[utils.MONETARY])
|
|
}
|
|
}
|
|
|
|
func TestActionRemoveExpiredBalance(t *testing.T) {
|
|
err := dm.SetAccount(&Account{
|
|
ID: "cgrates.org:rembal2",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Value: 10,
|
|
},
|
|
&Balance{
|
|
Value: 10,
|
|
DestinationIDs: utils.NewStringMap("NAT", "RET"),
|
|
ExpirationDate: time.Date(2025, time.November, 11, 22, 39, 0, 0, time.UTC),
|
|
},
|
|
&Balance{
|
|
Value: 10,
|
|
DestinationIDs: utils.NewStringMap("NAT", "RET"),
|
|
ExpirationDate: time.Date(2010, time.November, 11, 22, 39, 0, 0, time.UTC),
|
|
},
|
|
&Balance{
|
|
Value: 10,
|
|
DestinationIDs: utils.NewStringMap("NAT", "RET"),
|
|
ExpirationDate: time.Date(2012, time.November, 11, 22, 39, 0, 0, time.UTC),
|
|
},
|
|
},
|
|
},
|
|
Disabled: true,
|
|
})
|
|
if err != nil {
|
|
t.Error("Error setting account: ", err)
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:rembal2": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{
|
|
{
|
|
ActionType: utils.MetaRemoveExpired,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:rembal2")
|
|
if err != nil || acc == nil {
|
|
t.Errorf("Error getting account: %+v: %v", acc, err)
|
|
}
|
|
if len(acc.BalanceMap) != 1 ||
|
|
len(acc.BalanceMap[utils.MONETARY]) != 2 {
|
|
t.Errorf("Error removing balance: %+v", utils.ToJSON(acc.BalanceMap[utils.MONETARY]))
|
|
}
|
|
}
|
|
|
|
func TestActionTransferMonetaryDefault(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:trans",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
ID: utils.MetaDefault,
|
|
Value: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 3,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: -2,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.TRANSFER_MONETARY_DEFAULT,
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:trans": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:trans")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 17 ||
|
|
afterUb.BalanceMap[utils.MONETARY][0].Value != 19 ||
|
|
afterUb.BalanceMap[utils.MONETARY][1].Value != 0 ||
|
|
afterUb.BalanceMap[utils.MONETARY][2].Value != 0 ||
|
|
afterUb.BalanceMap[utils.MONETARY][3].Value != -2 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
|
|
}
|
|
}
|
|
|
|
func TestActionTransferMonetaryDefaultFilter(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:trans",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
ID: utils.MetaDefault,
|
|
Value: 10,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 3,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 1,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.TRANSFER_MONETARY_DEFAULT,
|
|
Balance: &BalanceFilter{Weight: utils.Float64Pointer(20)},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:trans": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:trans")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 20 ||
|
|
afterUb.BalanceMap[utils.MONETARY][0].Value != 19 ||
|
|
afterUb.BalanceMap[utils.MONETARY][1].Value != 0 ||
|
|
afterUb.BalanceMap[utils.MONETARY][2].Value != 1 ||
|
|
afterUb.BalanceMap[utils.MONETARY][3].Value != 0 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
|
|
}
|
|
}
|
|
|
|
func TestActionConditionalTopup(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:cond",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
ID: utils.MetaDefault,
|
|
Value: 10,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 3,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 1,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.TOPUP,
|
|
Filter: `{"Type":"*monetary","Value":1,"Weight":10}`,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 11},
|
|
Weight: utils.Float64Pointer(30),
|
|
},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:cond": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:cond")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if len(afterUb.BalanceMap[utils.MONETARY]) != 5 ||
|
|
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 31 ||
|
|
afterUb.BalanceMap[utils.MONETARY][4].Value != 11 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
|
|
}
|
|
}
|
|
|
|
func TestActionConditionalTopupNoMatch(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:cond",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
ID: utils.MetaDefault,
|
|
Value: 10,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 3,
|
|
Weight: 20,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 1,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.TOPUP,
|
|
Filter: `{"Type":"*monetary","Value":2,"Weight":10}`,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 11},
|
|
Weight: utils.Float64Pointer(30),
|
|
},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:cond": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:cond")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if len(afterUb.BalanceMap[utils.MONETARY]) != 4 ||
|
|
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 20 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
|
|
}
|
|
}
|
|
|
|
func TestActionConditionalTopupExistingBalance(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:cond",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 1,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
utils.VOICE: {
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 10,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
Uuid: utils.GenUUID(),
|
|
Value: 100,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.TOPUP,
|
|
Filter: `{"Type":"*voice","Value":{"*gte":100}}`,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 11},
|
|
Weight: utils.Float64Pointer(10),
|
|
},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:cond": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:cond")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if len(afterUb.BalanceMap[utils.MONETARY]) != 2 ||
|
|
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 18 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
|
|
}
|
|
}
|
|
|
|
func TestActionConditionalDisabledIfNegative(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:af",
|
|
BalanceMap: map[string]Balances{
|
|
"*data": {
|
|
&Balance{
|
|
Uuid: "fc927edb-1bd6-425e-a2a3-9fd8bafaa524",
|
|
ID: "for_v3hsillmilld500m_data_500_m",
|
|
Value: 5.242,
|
|
Weight: 10,
|
|
RatingSubject: "for_v3hsillmilld500m_data_forfait",
|
|
Categories: utils.StringMap{
|
|
"data_france": true,
|
|
},
|
|
},
|
|
},
|
|
"*monetary": {
|
|
&Balance{
|
|
Uuid: "9fa1847a-f36a-41a7-8ec0-dfaab370141e",
|
|
ID: utils.MetaDefault,
|
|
Value: -1.95001,
|
|
},
|
|
},
|
|
"*sms": {
|
|
&Balance{
|
|
Uuid: "d348d15d-2988-4ee4-b847-6a552f94e2ec",
|
|
ID: "for_v3hsillmilld500m_mms_ill",
|
|
Value: 20000,
|
|
Weight: 10,
|
|
DestinationIDs: utils.StringMap{
|
|
"FRANCE_NATIONAL": true,
|
|
},
|
|
Categories: utils.StringMap{
|
|
"mms_france": true,
|
|
"tmms_france": true,
|
|
"vmms_france": true,
|
|
},
|
|
},
|
|
&Balance{
|
|
Uuid: "f4643517-31f6-4199-980f-04cf535471ed",
|
|
ID: "for_v3hsillmilld500m_sms_ill",
|
|
Value: 20000,
|
|
Weight: 10,
|
|
DestinationIDs: utils.StringMap{
|
|
"FRANCE_NATIONAL": true,
|
|
},
|
|
Categories: utils.StringMap{
|
|
"ms_france": true,
|
|
},
|
|
},
|
|
},
|
|
"*voice": {
|
|
&Balance{
|
|
Uuid: "079ab190-77f4-44f3-9c6f-3a0dd1a59dfd",
|
|
ID: "for_v3hsillmilld500m_voice_3_h",
|
|
Value: 10800,
|
|
Weight: 10,
|
|
DestinationIDs: utils.StringMap{
|
|
"FRANCE_NATIONAL": true,
|
|
},
|
|
Categories: utils.StringMap{
|
|
"call_france": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a1 := &Action{
|
|
ActionType: utils.SET_BALANCE,
|
|
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"ID\":{\"*eq\":\"*default\"}}]}",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer("*sms"),
|
|
ID: utils.StringPointer("for_v3hsillmilld500m_sms_ill"),
|
|
Disabled: utils.BoolPointer(true),
|
|
},
|
|
Weight: 9,
|
|
}
|
|
a2 := &Action{
|
|
ActionType: utils.SET_BALANCE,
|
|
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"ID\":{\"*eq\":\"*default\"}}]}",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer("*sms"),
|
|
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: utils.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: utils.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,
|
|
}
|
|
a5 := &Action{
|
|
ActionType: utils.SET_BALANCE,
|
|
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"ID\":{\"*eq\":\"*default\"}}]}",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer("*voice"),
|
|
ID: utils.StringPointer("for_v3hsillmilld500m_voice_3_h"),
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("FRANCE_NATIONAL")),
|
|
Weight: utils.Float64Pointer(10),
|
|
Disabled: utils.BoolPointer(true),
|
|
},
|
|
Weight: 6,
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:af": true},
|
|
actions: Actions{a1, a2, a3, a4, a5},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:af")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
|
|
for btype, chain := range afterUb.BalanceMap {
|
|
if btype != utils.MONETARY {
|
|
for _, b := range chain {
|
|
if b.Disabled != true {
|
|
t.Errorf("Failed to disabled balance (%s): %+v", btype, b)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestActionSetBalance(t *testing.T) {
|
|
err := dm.SetAccount(
|
|
&Account{
|
|
ID: "cgrates.org:setb",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
ID: "m1",
|
|
Uuid: utils.GenUUID(),
|
|
Value: 1,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
ID: "m2",
|
|
Uuid: utils.GenUUID(),
|
|
Value: 6,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
utils.VOICE: {
|
|
&Balance{
|
|
ID: "v1",
|
|
Uuid: utils.GenUUID(),
|
|
Value: 10,
|
|
Weight: 10,
|
|
},
|
|
&Balance{
|
|
ID: "v2",
|
|
Uuid: utils.GenUUID(),
|
|
Value: 100,
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Errorf("error setting account: %v", err)
|
|
}
|
|
|
|
a := &Action{
|
|
ActionType: utils.SET_BALANCE,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer("m2"),
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 11},
|
|
Weight: utils.Float64Pointer(10),
|
|
},
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:setb": true},
|
|
actions: Actions{a},
|
|
}
|
|
at.Execute(nil, nil)
|
|
|
|
afterUb, err := dm.GetAccount("cgrates.org:setb")
|
|
if err != nil {
|
|
t.Error("account not found: ", err, afterUb)
|
|
}
|
|
if len(afterUb.BalanceMap[utils.MONETARY]) != 2 ||
|
|
afterUb.BalanceMap[utils.MONETARY][1].Value != 11 ||
|
|
afterUb.BalanceMap[utils.MONETARY][1].Weight != 10 {
|
|
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
|
|
t.Logf("B: %+v", b)
|
|
}
|
|
t.Errorf("Balance: %+v", afterUb.BalanceMap[utils.MONETARY][1])
|
|
}
|
|
}
|
|
|
|
func TestActionCSVFilter(t *testing.T) {
|
|
act, err := dm.GetActions("FILTER", false, utils.NonTransactional)
|
|
if err != nil {
|
|
t.Error("error getting actions: ", err)
|
|
}
|
|
if len(act) != 1 || act[0].Filter != `{"*and":[{"Value":{"*lt":0}},{"Id":{"*eq":"*default"}}]}` {
|
|
t.Error("Error loading actions: ", act[0].Filter)
|
|
}
|
|
}
|
|
|
|
func TestActionExpirationTime(t *testing.T) {
|
|
a, err := dm.GetActions("EXP", false, utils.NonTransactional)
|
|
if err != nil || a == nil {
|
|
t.Error("Error getting actions: ", err)
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:expo": true},
|
|
actions: a,
|
|
}
|
|
for rep := 0; rep < 5; rep++ {
|
|
at.Execute(nil, nil)
|
|
afterUb, err := dm.GetAccount("cgrates.org:expo")
|
|
if err != nil ||
|
|
len(afterUb.BalanceMap[utils.VOICE]) != rep+1 {
|
|
t.Error("error topuping expiration balance: ", utils.ToIJSON(afterUb))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestActionExpNoExp(t *testing.T) {
|
|
exp, err := dm.GetActions("EXP", false, utils.NonTransactional)
|
|
if err != nil || exp == nil {
|
|
t.Error("Error getting actions: ", err)
|
|
}
|
|
noexp, err := dm.GetActions("NOEXP", false, utils.NonTransactional)
|
|
if err != nil || noexp == nil {
|
|
t.Error("Error getting actions: ", err)
|
|
}
|
|
exp = append(exp, noexp...)
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:expnoexp": true},
|
|
actions: exp,
|
|
}
|
|
at.Execute(nil, nil)
|
|
afterUb, err := dm.GetAccount("cgrates.org:expnoexp")
|
|
if err != nil ||
|
|
len(afterUb.BalanceMap[utils.VOICE]) != 2 {
|
|
t.Error("error topuping expiration balance: ", utils.ToIJSON(afterUb))
|
|
}
|
|
}
|
|
|
|
func TestActionTopUpZeroNegative(t *testing.T) {
|
|
account := &Account{
|
|
ID: "cgrates.org:zeroNegative",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
ID: "Bal1",
|
|
Value: -10,
|
|
},
|
|
&Balance{
|
|
ID: "Bal2",
|
|
Value: 5,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err := dm.SetAccount(account)
|
|
if err != nil {
|
|
t.Error("Error setting account: ", err)
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:zeroNegative": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{
|
|
{
|
|
Id: "ZeroMonetary",
|
|
ActionType: utils.TopUpZeroNegative,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:zeroNegative")
|
|
if err != nil || acc == nil {
|
|
t.Error("Error getting account: ", acc, err)
|
|
}
|
|
//Verify value for first balance(Bal1) should be 0 after execute action TopUpZeroNegative
|
|
if acc.BalanceMap[utils.MONETARY][0].Value != 0 {
|
|
t.Errorf("Expecting 0, received: %+v", acc.BalanceMap[utils.MONETARY][0].Value)
|
|
}
|
|
//Verify value for secound balance(Bal2) should be the same
|
|
if acc.BalanceMap[utils.MONETARY][1].Value != 5 {
|
|
t.Errorf("Expecting 5, received: %+v", acc.BalanceMap[utils.MONETARY][1].Value)
|
|
}
|
|
}
|
|
|
|
func TestActionSetExpiry(t *testing.T) {
|
|
timeNowPlus24h := time.Now().Add(time.Duration(24 * time.Hour))
|
|
account := &Account{
|
|
ID: "cgrates.org:zeroNegative",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: {
|
|
&Balance{
|
|
ID: "Bal1",
|
|
Value: -10,
|
|
},
|
|
&Balance{
|
|
ID: "Bal2",
|
|
Value: 5,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err := dm.SetAccount(account)
|
|
if err != nil {
|
|
t.Error("Error setting account: ", err)
|
|
}
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:zeroNegative": true},
|
|
Timing: &RateInterval{},
|
|
actions: []*Action{
|
|
{
|
|
Id: "SetExpiry",
|
|
ActionType: utils.SetExpiry,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer("Bal1"),
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
ExpirationDate: utils.TimePointer(timeNowPlus24h),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
err = at.Execute(nil, nil)
|
|
acc, err := dm.GetAccount("cgrates.org:zeroNegative")
|
|
if err != nil || acc == nil {
|
|
t.Error("Error getting account: ", acc, err)
|
|
}
|
|
//Verify ExpirationDate for first balance(Bal1)
|
|
if !acc.BalanceMap[utils.MONETARY][0].ExpirationDate.Equal(timeNowPlus24h) {
|
|
t.Errorf("Expecting: %+v, received: %+v", timeNowPlus24h, acc.BalanceMap[utils.MONETARY][0].ExpirationDate)
|
|
}
|
|
}
|
|
|
|
type TestRPCParameters struct {
|
|
status string
|
|
}
|
|
|
|
type Attr struct {
|
|
Name string
|
|
Surname string
|
|
Age float64
|
|
}
|
|
|
|
func (trpcp *TestRPCParameters) Hopa(in Attr, out *float64) error {
|
|
trpcp.status = utils.OK
|
|
return nil
|
|
}
|
|
|
|
func (trpcp *TestRPCParameters) Call(ctx *context.Context, serviceMethod string, args any, reply any) error {
|
|
parts := strings.Split(serviceMethod, ".")
|
|
if len(parts) != 2 {
|
|
return utils.ErrNotImplemented
|
|
}
|
|
// get method
|
|
method := reflect.ValueOf(trpcp).MethodByName(parts[1])
|
|
if !method.IsValid() {
|
|
return utils.ErrNotImplemented
|
|
}
|
|
|
|
// construct the params
|
|
params := []reflect.Value{reflect.ValueOf(args).Elem(), reflect.ValueOf(reply)}
|
|
|
|
ret := method.Call(params)
|
|
if len(ret) != 1 {
|
|
return utils.ErrServerError
|
|
}
|
|
if ret[0].Interface() == nil {
|
|
return nil
|
|
}
|
|
err, ok := ret[0].Interface().(error)
|
|
if !ok {
|
|
return utils.ErrServerError
|
|
}
|
|
return err
|
|
}
|
|
|
|
func TestCgrRpcAction(t *testing.T) {
|
|
trpcp := &TestRPCParameters{}
|
|
utils.RegisterRpcParams("", trpcp)
|
|
a := &Action{
|
|
ExtraParameters: `{"Address": "*internal",
|
|
"Transport": "*gob",
|
|
"Method": "TestRPCParameters.Hopa",
|
|
"Attempts":1,
|
|
"Async" :false,
|
|
"Params": {"Name":"n", "Surname":"s", "Age":10.2}}`,
|
|
}
|
|
if err := cgrRPCAction(nil, a, nil, nil); err != nil {
|
|
t.Error("error executing cgr action: ", err)
|
|
}
|
|
if trpcp.status != utils.OK {
|
|
t.Error("RPC not called!")
|
|
}
|
|
}
|
|
|
|
func TestValueFormulaDebit(t *testing.T) {
|
|
if _, err := dm.GetAccount("cgrates.org:vf"); err != nil {
|
|
t.Errorf("account to be removed not found: %v", err)
|
|
}
|
|
|
|
at := &ActionTiming{
|
|
accountIDs: utils.StringMap{"cgrates.org:vf": true},
|
|
ActionsID: "VF",
|
|
}
|
|
at.Execute(nil, nil)
|
|
afterUb, err := dm.GetAccount("cgrates.org:vf")
|
|
// not an exact value, depends of month
|
|
v := afterUb.BalanceMap[utils.MONETARY].GetTotalValue()
|
|
if err != nil || v > -0.30 || v < -0.36 {
|
|
t.Error("error debiting account: ", err, utils.ToIJSON(afterUb), v)
|
|
}
|
|
}
|
|
|
|
func TestClonedAction(t *testing.T) {
|
|
a := &Action{
|
|
Id: "test1",
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer(utils.MetaDefault),
|
|
Value: &utils.ValueFormula{Static: 1},
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
Weight: float64(10),
|
|
}
|
|
if clone := a.Clone(); !reflect.DeepEqual(a, clone) {
|
|
t.Error("error cloning action: ", utils.ToIJSON(clone))
|
|
}
|
|
}
|
|
|
|
func TestClonedActions(t *testing.T) {
|
|
actions := Actions{
|
|
&Action{
|
|
Id: "RECUR_FOR_V3HSILLMILLD1G",
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer(utils.MetaDefault),
|
|
Value: &utils.ValueFormula{Static: 1},
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
Weight: float64(30),
|
|
},
|
|
&Action{
|
|
Id: "RECUR_FOR_V3HSILLMILLD5G",
|
|
ActionType: utils.DEBIT,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer(utils.MetaDefault),
|
|
Value: &utils.ValueFormula{Static: 2},
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
Weight: float64(20),
|
|
},
|
|
}
|
|
if clone, err := actions.Clone(); err != nil {
|
|
t.Error("error cloning actions: ", err)
|
|
} else if !reflect.DeepEqual(actions, clone) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToIJSON(actions), utils.ToIJSON(clone))
|
|
}
|
|
|
|
}
|
|
|
|
func TestCacheGetClonedActions(t *testing.T) {
|
|
actions := Actions{
|
|
&Action{
|
|
Id: "RECUR_FOR_V3HSILLMILLD1G",
|
|
ActionType: utils.TOPUP,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer(utils.MetaDefault),
|
|
Value: &utils.ValueFormula{Static: 1},
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
},
|
|
Weight: float64(30),
|
|
},
|
|
&Action{
|
|
Id: "REACT_FOR_V3HSILLMILL",
|
|
ActionType: utils.SET_BALANCE,
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer("for_v3hsillmill_sms_ill"),
|
|
Type: utils.StringPointer(utils.SMS),
|
|
Value: &utils.ValueFormula{Static: 20000},
|
|
DestinationIDs: &utils.StringMap{
|
|
"FRANCE_NATIONAL": true,
|
|
"FRANCE_NATIONAL_FREE": false,
|
|
"ZONE1": false},
|
|
Categories: &utils.StringMap{
|
|
"sms_eurotarif": true,
|
|
"sms_france": true},
|
|
Disabled: utils.BoolPointer(false),
|
|
Blocker: utils.BoolPointer(false),
|
|
},
|
|
Weight: float64(10),
|
|
},
|
|
}
|
|
Cache.Set(utils.CacheActions, "MYTEST", actions, nil, true, "")
|
|
clned, err := Cache.GetCloned(utils.CacheActions, "MYTEST")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
aCloned := clned.(Actions)
|
|
if !reflect.DeepEqual(actions, aCloned) {
|
|
t.Errorf("Expecting: %+v, received: %+v", actions[1].Balance, aCloned[1].Balance)
|
|
}
|
|
}
|
|
|
|
func TestRemoveSessionCosts(t *testing.T) {
|
|
cfg, _ := config.NewDefaultCGRConfig()
|
|
db := NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items)
|
|
tmpDM := dm
|
|
dm := NewDataManager(db, cfg.CacheCfg(), nil)
|
|
defer func() {
|
|
SetCdrStorage(cdrStorage)
|
|
SetDataStorage(tmpDM)
|
|
}()
|
|
aT := &ActionTiming{
|
|
ActionsID: "ACT_LOG",
|
|
}
|
|
SetDataStorage(dm)
|
|
SetCdrStorage(db)
|
|
fltrs := []*Filter{
|
|
{
|
|
Tenant: "cgrates.org",
|
|
ID: "FLTR_1",
|
|
Rules: []*FilterRule{
|
|
{
|
|
Element: utils.DynamicDataPrefix + utils.RunID,
|
|
Type: utils.MetaString,
|
|
Values: []string{"RunID"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Tenant: "cgrates.org",
|
|
ID: "FLTR_2",
|
|
Rules: []*FilterRule{
|
|
{
|
|
Type: utils.MetaGreaterOrEqual,
|
|
Element: "~Usage",
|
|
Values: []string{"12s", "33s"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, fltr := range fltrs {
|
|
dm.SetFilter(fltr)
|
|
}
|
|
acs := Actions{
|
|
{
|
|
ActionType: utils.MetaRemoveSessionCosts,
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 25},
|
|
DestinationIDs: utils.StringMapPointer(utils.NewStringMap("RET")),
|
|
Weight: utils.Float64Pointer(20)},
|
|
ExtraParameters: "FLTR_1;FLTR_2",
|
|
},
|
|
}
|
|
smCost := &SMCost{
|
|
RunID: "RunID",
|
|
Usage: 12 * time.Second,
|
|
CostDetails: &EventCost{
|
|
CGRID: "EventCost_CGRID",
|
|
Cost: utils.Float64Pointer(0.74),
|
|
},
|
|
}
|
|
if err := db.SetSMCost(smCost); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dm.SetActions("ACT_LOG", acs, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := aT.Execute(nil, nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestActionSetDestinations(t *testing.T) {
|
|
cfg, _ := config.NewDefaultCGRConfig()
|
|
tmpConn := connMgr
|
|
tmpDm := dm
|
|
defer func() {
|
|
cfg2, _ := config.NewDefaultCGRConfig()
|
|
config.SetCgrConfig(cfg2)
|
|
SetConnManager(tmpConn)
|
|
SetDataStorage(tmpDm)
|
|
}()
|
|
cfg.RalsCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS)}
|
|
ddc := &StatDDC{
|
|
FieldValues: map[string]map[string]struct{}{
|
|
"1001": {
|
|
"EVENT_1": {},
|
|
},
|
|
"1002": {
|
|
"EVENT_3": {},
|
|
},
|
|
},
|
|
MinItems: 2,
|
|
Count: 3,
|
|
}
|
|
|
|
clientConn := make(chan birpc.ClientConnector, 1)
|
|
clientConn <- clMock(func(ctx *context.Context, serviceMethod string, _, reply any) error {
|
|
if serviceMethod == utils.StatSv1GetStatQueue {
|
|
rpl := &StatQueue{
|
|
Tenant: "cgrates.org",
|
|
SQMetrics: map[string]StatMetric{
|
|
utils.MetaDDC: ddc,
|
|
},
|
|
}
|
|
*reply.(*StatQueue) = *rpl
|
|
return nil
|
|
}
|
|
return utils.ErrNotImplemented
|
|
})
|
|
connMgr := NewConnManager(cfg, map[string]chan birpc.ClientConnector{
|
|
utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS): clientConn,
|
|
})
|
|
dm := NewDataManager(NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items), cfg.CacheCfg(), nil)
|
|
ub := &Account{
|
|
ID: "cgrates.org:1001",
|
|
BalanceMap: map[string]Balances{
|
|
utils.VOICE: {
|
|
&Balance{Value: 20 * float64(time.Second),
|
|
DestinationIDs: utils.NewStringMap(utils.MetaDDC + "DST1"),
|
|
Weight: 10},
|
|
&Balance{Value: 100 * float64(time.Second),
|
|
DestinationIDs: utils.NewStringMap("DST2"), Weight: 20},
|
|
}},
|
|
}
|
|
a := &Action{
|
|
ActionType: utils.ENABLE_ACCOUNT,
|
|
ExtraParameters: "SQ1;SQ2",
|
|
Balance: &BalanceFilter{
|
|
Type: utils.StringPointer(utils.VOICE),
|
|
Weight: utils.Float64Pointer(10),
|
|
},
|
|
}
|
|
dm.SetDestination(&Destination{
|
|
Id: utils.MetaDDC + "DST1",
|
|
Prefixes: []string{
|
|
"1003", "1004",
|
|
},
|
|
}, "")
|
|
config.SetCgrConfig(cfg)
|
|
SetConnManager(connMgr)
|
|
SetDataStorage(dm)
|
|
if err := setddestinations(ub, a, nil, nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestActionRemBalanceActionErr(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
ub *Account
|
|
a *Action
|
|
acs Actions
|
|
}{
|
|
{
|
|
name: "Nil Account Error",
|
|
},
|
|
{
|
|
name: "Balance Not Found",
|
|
ub: &Account{
|
|
ID: "cgrates.org:1001",
|
|
BalanceMap: map[string]Balances{
|
|
utils.VOICE: {
|
|
&Balance{Value: 20 * float64(time.Second),
|
|
DestinationIDs: utils.NewStringMap("1002"),
|
|
Weight: 10, RatingSubject: "rif"},
|
|
}},
|
|
},
|
|
a: &Action{
|
|
ActionType: "*topup",
|
|
Balance: &BalanceFilter{Type: utils.StringPointer(utils.MONETARY),
|
|
Value: &utils.ValueFormula{Static: 10}},
|
|
},
|
|
},
|
|
{
|
|
name: "Unmatched Balance",
|
|
ub: &Account{
|
|
ID: "cgrates.org:1001",
|
|
BalanceMap: map[string]Balances{
|
|
utils.VOICE: {
|
|
&Balance{
|
|
ID: "balance_id",
|
|
Value: 20 * float64(time.Second),
|
|
DestinationIDs: utils.NewStringMap("1002"),
|
|
Weight: 10, RatingSubject: "rif"},
|
|
}},
|
|
},
|
|
a: &Action{
|
|
ActionType: "*topup",
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer("balance_id2"),
|
|
Type: utils.StringPointer(utils.VOICE),
|
|
Value: &utils.ValueFormula{Static: 10}},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if err := removeBalanceAction(tc.ub, tc.a, tc.acs, nil); err == nil {
|
|
t.Errorf("Expected error received nil")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCdrLogAction
|
|
type RPCMock struct {
|
|
args *ArgV1ProcessEvent
|
|
}
|
|
|
|
func (r *RPCMock) Call(method string, args any, rply any) error {
|
|
if method != utils.CDRsV1ProcessEvent {
|
|
return rpcclient.ErrUnsupporteServiceMethod
|
|
}
|
|
if r.args != nil {
|
|
return fmt.Errorf("There should be only one call to this function")
|
|
}
|
|
r.args = args.(*ArgV1ProcessEvent)
|
|
rp := rply.(*string)
|
|
*rp = utils.OK
|
|
return nil
|
|
}
|
|
|
|
/*
|
|
NEED TO REVIEW THIS TEST
|
|
func TestCdrLogAction(t *testing.T) {
|
|
bakSch := schedCdrsConns
|
|
mock := RPCMock{}
|
|
schedCdrsConns = &mock
|
|
defer func() { schedCdrsConns = bakSch }()
|
|
|
|
var extraData any
|
|
acc := &Account{
|
|
ID: "cgrates.org:1001",
|
|
BalanceMap: map[string]Balances{
|
|
utils.MONETARY: Balances{
|
|
&Balance{Value: 20},
|
|
},
|
|
},
|
|
UnitCounters: UnitCounters{
|
|
utils.MONETARY: []*UnitCounter{
|
|
&UnitCounter{
|
|
Counters: CounterFilters{
|
|
&CounterFilter{Value: 1},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
a := &Action{
|
|
Id: "CDRLog1",
|
|
ActionType: utils.CDRLOG,
|
|
ExtraParameters: "{\"BalanceID\":\"~BalanceID\",\"ActionID\":\"~ActionID\",\"BalanceValue\":\"~BalanceValue\"}",
|
|
Weight: 50,
|
|
}
|
|
acs := Actions{
|
|
a,
|
|
&Action{
|
|
Id: "CdrDebit",
|
|
ActionType: "*debit",
|
|
Balance: &BalanceFilter{
|
|
ID: utils.StringPointer(utils.MetaDefault),
|
|
Value: &utils.ValueFormula{Static: 9.95},
|
|
Type: utils.StringPointer(utils.MONETARY),
|
|
Weight: utils.Float64Pointer(0),
|
|
},
|
|
Weight: float64(90),
|
|
balanceValue: 10,
|
|
},
|
|
}
|
|
if err := cdrLogAction(acc, a, acs, extraData); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mock.args == nil {
|
|
t.Fatalf("Expected a call to %s", utils.CDRsV1ProcessEvent)
|
|
}
|
|
expCgrEv := utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: mock.args.CGREvent.ID,
|
|
Event: map[string]any
|
|
"Account": "1001",
|
|
"ActionID": "CdrDebit",
|
|
"AnswerTime": mock.args.CGREvent.Event["AnswerTime"],
|
|
"BalanceID": "*default",
|
|
"BalanceValue": "10",
|
|
"CGRID": mock.args.CGREvent.Event["CGRID"],
|
|
"Category": "",
|
|
"Cost": 9.95,
|
|
"CostSource": "",
|
|
"Destination": "",
|
|
"ExtraInfo": "",
|
|
"OrderID": mock.args.CGREvent.Event["OrderID"],
|
|
"OriginHost": "127.0.0.1",
|
|
"OriginID": mock.args.CGREvent.Event["OriginID"],
|
|
"Partial": false,
|
|
"PreRated": true,
|
|
"RequestType": "*none",
|
|
"RunID": "*debit",
|
|
"SetupTime": mock.args.CGREvent.Event["SetupTime"],
|
|
"Source": utils.CDRLOG,
|
|
"Subject": "1001",
|
|
"Tenant": "cgrates.org",
|
|
"ToR": "*monetary",
|
|
"Usage": mock.args.CGREvent.Event["Usage"],
|
|
},
|
|
}
|
|
if !reflect.DeepEqual(expCgrEv, mock.args.CGREvent) {
|
|
t.Errorf("Expected: %s ,received: %s", utils.ToJSON(expCgrEv), utils.ToJSON(mock.args.CGREvent))
|
|
}
|
|
}
|
|
*/
|
|
/**************** Benchmarks ********************************/
|
|
|
|
func BenchmarkUUID(b *testing.B) {
|
|
m := make(map[string]int, 1000)
|
|
for i := 0; i < b.N; i++ {
|
|
uuid := utils.GenUUID()
|
|
if len(uuid) == 0 {
|
|
b.Fatalf("GenUUID error %s", uuid)
|
|
}
|
|
b.StopTimer()
|
|
c := m[uuid]
|
|
if c > 0 {
|
|
b.Fatalf("duplicate uuid[%s] count %d", uuid, c)
|
|
}
|
|
m[uuid] = c + 1
|
|
b.StartTimer()
|
|
}
|
|
}
|