mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-25 09:08:45 +05:00
added tests on thresholds processing
This commit is contained in:
committed by
Dan Christian Bogos
parent
f3ca5b0016
commit
fbb625962c
@@ -768,3 +768,122 @@ func TestCheckDefaultTiming(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestActionTimingGetNextStartTime2(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
actionTiming *ActionTiming
|
||||
startTime time.Time
|
||||
expectedTime time.Time
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "MonthlyEstimatedTiming",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: &RateInterval{
|
||||
Timing: &RITiming{
|
||||
ID: utils.MetaMonthlyEstimated,
|
||||
StartTime: "00:00:00",
|
||||
Years: []int{2024},
|
||||
Months: []time.Month{1, 2, 3},
|
||||
MonthDays: []int{31},
|
||||
},
|
||||
},
|
||||
},
|
||||
startTime: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Date(2024, 1, 31, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "WeekDaysCron",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: &RateInterval{
|
||||
Timing: &RITiming{
|
||||
StartTime: "09:00:00",
|
||||
Years: []int{2024},
|
||||
Months: []time.Month{1, 2, 3},
|
||||
MonthDays: []int{1, 15},
|
||||
WeekDays: []time.Weekday{time.Monday, time.Wednesday, time.Friday},
|
||||
EndTime: "17:00:00",
|
||||
},
|
||||
},
|
||||
},
|
||||
startTime: time.Date(2024, 1, 1, 10, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Date(2024, 1, 3, 9, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "YearTransition",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: &RateInterval{
|
||||
Timing: &RITiming{
|
||||
StartTime: "00:00:00",
|
||||
Years: []int{2024, 2025},
|
||||
Months: []time.Month{12, 1},
|
||||
MonthDays: []int{31, 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
startTime: time.Date(2024, 12, 31, 23, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "LeapYear",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: &RateInterval{
|
||||
Timing: &RITiming{
|
||||
StartTime: "00:00:00",
|
||||
Years: []int{2024},
|
||||
Months: []time.Month{2},
|
||||
MonthDays: []int{29},
|
||||
},
|
||||
},
|
||||
},
|
||||
startTime: time.Date(2024, 2, 28, 0, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Date(2024, 2, 29, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "NilTiming",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: nil,
|
||||
},
|
||||
startTime: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Time{},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "EmptyTiming",
|
||||
actionTiming: &ActionTiming{
|
||||
Timing: &RateInterval{
|
||||
Timing: nil,
|
||||
},
|
||||
},
|
||||
startTime: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
expectedTime: time.Time{},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
if tt.actionTiming != nil {
|
||||
tt.actionTiming.ResetStartTimeCache()
|
||||
}
|
||||
|
||||
result := tt.actionTiming.GetNextStartTime(tt.startTime)
|
||||
|
||||
if tt.expectedError {
|
||||
if !result.IsZero() {
|
||||
t.Errorf("Expected zero time for error case, got: %v", result)
|
||||
}
|
||||
return
|
||||
}
|
||||
if !result.Equal(tt.expectedTime) {
|
||||
t.Errorf("GetNextStartTime(%v) = %v; want %v",
|
||||
tt.startTime, result, tt.expectedTime)
|
||||
}
|
||||
cachedResult := tt.actionTiming.GetNextStartTime(tt.startTime)
|
||||
if !cachedResult.Equal(result) {
|
||||
t.Errorf("Cached result differs: got %v, want %v",
|
||||
cachedResult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3451,3 +3451,101 @@ func TestFilterToSQLQueryValidations(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeightFromDynamics2(t *testing.T) {
|
||||
cfg := config.NewDefaultCGRConfig()
|
||||
connMgr = NewConnManager(cfg, nil)
|
||||
db, _ := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
|
||||
dm := NewDataManager(db, cfg.CacheCfg(), nil)
|
||||
filterS := NewFilterS(cfg, connMgr, dm)
|
||||
testCases := []struct {
|
||||
name string
|
||||
dynamicWeights []*utils.DynamicWeight
|
||||
tenant string
|
||||
event utils.DataProvider
|
||||
expectedWeight float64
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "EmptyDynamicWeight",
|
||||
dynamicWeights: []*utils.DynamicWeight{},
|
||||
tenant: "cgrates.org",
|
||||
event: utils.MapStorage{},
|
||||
expectedWeight: 0.0,
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "MatchingWeight",
|
||||
dynamicWeights: []*utils.DynamicWeight{
|
||||
{
|
||||
FilterIDs: []string{"*string:~*req.Account:1001"},
|
||||
Weight: 10.0,
|
||||
},
|
||||
},
|
||||
tenant: "cgrates.org",
|
||||
event: utils.MapStorage{
|
||||
"*req": utils.MapStorage{
|
||||
"Account": "1001",
|
||||
},
|
||||
},
|
||||
expectedWeight: 10.0,
|
||||
},
|
||||
{
|
||||
name: "MultipleMatchingWeights",
|
||||
dynamicWeights: []*utils.DynamicWeight{
|
||||
{
|
||||
FilterIDs: []string{"*prefix:~*req.Destination:GER"},
|
||||
Weight: 10.0,
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{"*string:~*opts.subsys:*sessions"},
|
||||
Weight: 5.0,
|
||||
},
|
||||
},
|
||||
tenant: "cgrates.org",
|
||||
event: utils.MapStorage{
|
||||
"*req": utils.MapStorage{
|
||||
"Destination": "GER_0055",
|
||||
},
|
||||
"*opts": utils.MapStorage{
|
||||
"*subsys": "*sessions",
|
||||
},
|
||||
},
|
||||
expectedWeight: 10.0,
|
||||
},
|
||||
{
|
||||
name: "NoMatchingWeightFilterErr",
|
||||
dynamicWeights: []*utils.DynamicWeight{
|
||||
{
|
||||
FilterIDs: []string{"FLTR1"},
|
||||
Weight: 10.0,
|
||||
},
|
||||
},
|
||||
tenant: "cgrates.org",
|
||||
event: utils.MapStorage{
|
||||
"*req": utils.MapStorage{
|
||||
"Account": "1001",
|
||||
},
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
weight, err := WeightFromDynamics(tc.dynamicWeights, filterS, tc.tenant, tc.event)
|
||||
if tc.expectedErr {
|
||||
if err == nil {
|
||||
t.Error("Expected error but got none")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if weight != tc.expectedWeight {
|
||||
t.Errorf("Expected weight %v, got %v", tc.expectedWeight, weight)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -2163,3 +2164,77 @@ func TestThresholdsStoreThresholdCacheSetErr(t *testing.T) {
|
||||
|
||||
utils.Logger.SetLogLevel(0)
|
||||
}
|
||||
|
||||
func TestThresholdProcessEvent(t *testing.T) {
|
||||
cfg := config.NewDefaultCGRConfig()
|
||||
cfg.ThresholdSCfg().IndexedSelects = false
|
||||
db, _ := NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
|
||||
dm := NewDataManager(db, cfg.CacheCfg(), nil)
|
||||
fS := NewFilterS(cfg, nil, dm)
|
||||
ths := NewThresholdService(dm, cfg, fS, nil)
|
||||
thps := []*ThresholdProfile{
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TH1",
|
||||
FilterIDs: []string{"*string:~*req.Account:1001"},
|
||||
MinHits: 3,
|
||||
MaxHits: 2,
|
||||
},
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TH2",
|
||||
FilterIDs: []string{"*string:~*req.Account:1002"},
|
||||
MinHits: 2,
|
||||
MaxHits: 3,
|
||||
}, {
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TH3",
|
||||
FilterIDs: []string{"*string:~*req.Account:1003"},
|
||||
MinHits: 1,
|
||||
MaxHits: -1,
|
||||
},
|
||||
}
|
||||
for _, thP := range thps {
|
||||
if err := ths.dm.SetThresholdProfile(thP, false); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
tts := []struct {
|
||||
name string
|
||||
runs int
|
||||
cgrEvnt map[string]any
|
||||
matchedthIDs []string
|
||||
}{
|
||||
{
|
||||
name: "MinHitsLargerThanMaxHits",
|
||||
runs: 3,
|
||||
cgrEvnt: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MinHitsLargerThanMaxHits",
|
||||
runs: 4,
|
||||
cgrEvnt: map[string]any{
|
||||
utils.AccountField: "1002",
|
||||
},
|
||||
},
|
||||
{},
|
||||
}
|
||||
for _, tt := range tts {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var thIDs []string
|
||||
for range tt.runs {
|
||||
var err error
|
||||
thIDs, err = ths.processEvent("cgrates.org", &utils.CGREvent{Event: tt.cgrEvnt})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
if !slices.Equal(thIDs, tt.matchedthIDs) {
|
||||
t.Errorf("expected: %v, received: %v", tt.matchedthIDs, thIDs)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,3 +978,175 @@ func TestEngineUnitCounterString(t *testing.T) {
|
||||
t.Errorf("Expected JSON: %s, got: %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetCounters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
initialCounters UnitCounters
|
||||
action *Action
|
||||
expectedCounters UnitCounters
|
||||
}{
|
||||
{
|
||||
name: "ResetAlCountersNilAction",
|
||||
initialCounters: UnitCounters{
|
||||
utils.MetaMonetary: []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 100.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON1")}},
|
||||
{Value: 200.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON2")}},
|
||||
},
|
||||
},
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 50.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON1")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
utils.MetaVoice: []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 150.0, Filter: &BalanceFilter{ID: utils.StringPointer("VOICE1")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action: nil,
|
||||
expectedCounters: UnitCounters{
|
||||
utils.MetaMonetary: []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 0.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON1")}},
|
||||
{Value: 0.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON2")}},
|
||||
},
|
||||
},
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 0.0, Filter: &BalanceFilter{ID: utils.StringPointer("BAL_MON1")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
utils.MetaVoice: []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 0.0, Filter: &BalanceFilter{ID: utils.StringPointer("VOICE1")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ResetCountersMonetaryBalanceType",
|
||||
initialCounters: UnitCounters{
|
||||
"*monetary": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 100.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON1")}},
|
||||
{Value: 200.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON2")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"*data": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 50.0, Filter: &BalanceFilter{ID: utils.StringPointer("MB_BAL")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action: &Action{
|
||||
Balance: &BalanceFilter{Type: utils.StringPointer("*monetary")},
|
||||
},
|
||||
expectedCounters: UnitCounters{
|
||||
"*monetary": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 100.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON1")}},
|
||||
{Value: 200.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON2")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"*data": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 50.0, Filter: &BalanceFilter{ID: utils.StringPointer("MB_BAL")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ResetSpecificBalanceType",
|
||||
initialCounters: UnitCounters{
|
||||
"*monetary": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 100.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON1"), Type: utils.StringPointer("*monetary")}},
|
||||
{Value: 200.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON2"), Type: utils.StringPointer("*monetary")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action: &Action{
|
||||
Balance: &BalanceFilter{ID: utils.StringPointer("MON1"), Type: utils.StringPointer("*monetary")},
|
||||
},
|
||||
expectedCounters: UnitCounters{
|
||||
"*monetary": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaBalance,
|
||||
Counters: CounterFilters{
|
||||
{Value: 0.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON1"), Type: utils.StringPointer("*monetary")}},
|
||||
{Value: 200.0, Filter: &BalanceFilter{ID: utils.StringPointer("MON2"), Type: utils.StringPointer("*monetary")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ActionBalanceTypeNotExist",
|
||||
initialCounters: UnitCounters{
|
||||
"*data": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 150.0, Filter: &BalanceFilter{ID: utils.StringPointer("DATA1"), Type: utils.StringPointer("*data")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action: &Action{
|
||||
Balance: &BalanceFilter{Type: utils.StringPointer("*monetary")},
|
||||
},
|
||||
expectedCounters: UnitCounters{
|
||||
"*data": []*UnitCounter{
|
||||
{
|
||||
CounterType: utils.MetaCounterEvent,
|
||||
Counters: CounterFilters{
|
||||
{Value: 150.0, Filter: &BalanceFilter{ID: utils.StringPointer("DATA1"), Type: utils.StringPointer("*data")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cloneInitialCounters := tt.initialCounters.Clone()
|
||||
cloneInitialCounters.resetCounters(tt.action)
|
||||
if !reflect.DeepEqual(cloneInitialCounters, tt.expectedCounters) {
|
||||
t.Errorf("mismatch after resetCounters.\nExpected:\n%s\nGot:\n%s",
|
||||
utils.ToJSON(tt.expectedCounters), utils.ToJSON(cloneInitialCounters))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user