mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
1079 lines
31 KiB
Go
1079 lines
31 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 (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cgrates/cgrates/utils"
|
|
"github.com/google/go-cmp/cmp"
|
|
)
|
|
|
|
func TestBalanceSortPrecision(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 2}
|
|
mb2 := &Balance{Weight: 2, precision: 1}
|
|
var bs Balances
|
|
bs = append(bs, mb2, mb1)
|
|
bs.Sort()
|
|
if bs[0] != mb1 || bs[1] != mb2 {
|
|
t.Error("Buckets not sorted by weight!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortPrecisionWeightEqual(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 2}
|
|
mb2 := &Balance{Weight: 1, precision: 1}
|
|
var bs Balances
|
|
bs = append(bs, mb2, mb1)
|
|
bs.Sort()
|
|
if bs[0] != mb1 || bs[1] != mb2 {
|
|
t.Error("Buckets not sorted by precision!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortPrecisionWeightGreater(t *testing.T) {
|
|
mb1 := &Balance{Weight: 2, precision: 2}
|
|
mb2 := &Balance{Weight: 1, precision: 1}
|
|
var bs Balances
|
|
bs = append(bs, mb2, mb1)
|
|
bs.Sort()
|
|
if bs[0] != mb1 || bs[1] != mb2 {
|
|
t.Error("Buckets not sorted by precision!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortWeight(t *testing.T) {
|
|
mb1 := &Balance{Weight: 2, precision: 1}
|
|
mb2 := &Balance{Weight: 1, precision: 1}
|
|
var bs Balances
|
|
bs = append(bs, mb2, mb1)
|
|
bs.Sort()
|
|
if bs[0] != mb1 || bs[1] != mb2 {
|
|
t.Error("Buckets not sorted by precision!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortWeight2(t *testing.T) {
|
|
bs := Balances{
|
|
&Balance{ID: "B1", Weight: 2, precision: 1},
|
|
&Balance{ID: "B2", Weight: 1, precision: 1},
|
|
}
|
|
bs.Sort()
|
|
if bs[0].ID != "B1" && bs[1].ID != "B2" {
|
|
t.Error("Buckets not sorted by precision!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortWeight3(t *testing.T) {
|
|
bs := Balances{
|
|
&Balance{ID: "B1", Weight: 2, Value: 10.0},
|
|
&Balance{ID: "B2", Weight: 4, Value: 10.0},
|
|
}
|
|
bs.Sort()
|
|
if bs[0].ID != "B2" && bs[1].ID != "B1" {
|
|
t.Error(utils.ToJSON(bs))
|
|
}
|
|
}
|
|
|
|
func TestBalanceSortWeightLess(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 1}
|
|
mb2 := &Balance{Weight: 2, precision: 1}
|
|
var bs Balances
|
|
bs = append(bs, mb2, mb1)
|
|
bs.Sort()
|
|
if bs[0] != mb2 || bs[1] != mb1 {
|
|
t.Error("Buckets not sorted by precision!")
|
|
}
|
|
}
|
|
|
|
func TestBalanceEqual(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIDs: utils.StringMap{}}
|
|
mb2 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIDs: utils.StringMap{}}
|
|
mb3 := &Balance{Weight: 1, precision: 1, RatingSubject: "2", DestinationIDs: utils.StringMap{}}
|
|
if !mb1.Equal(mb2) || mb2.Equal(mb3) {
|
|
t.Error("Equal failure!", mb1 == mb2, mb3)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchFilter(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIDs: utils.StringMap{}}
|
|
mb2 := &BalanceFilter{Weight: utils.Float64Pointer(1), RatingSubject: nil, DestinationIDs: nil}
|
|
if !mb1.MatchFilter(mb2, "", false, false) {
|
|
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
|
|
}
|
|
|
|
mb1.Uuid, mb2.Uuid = "id", utils.StringPointer("id")
|
|
if !mb1.MatchFilter(mb2, "", false, false) {
|
|
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
|
|
}
|
|
|
|
}
|
|
|
|
func TestBalanceMatchFilterEmpty(t *testing.T) {
|
|
mb1 := &Balance{Weight: 1, precision: 1, RatingSubject: "1", DestinationIDs: utils.StringMap{}}
|
|
mb2 := &BalanceFilter{}
|
|
if !mb1.MatchFilter(mb2, "", false, false) {
|
|
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchFilterId(t *testing.T) {
|
|
mb1 := &Balance{ID: "T1", Weight: 2, precision: 2, RatingSubject: "2", DestinationIDs: utils.NewStringMap("NAT")}
|
|
mb2 := &BalanceFilter{ID: utils.StringPointer("T1"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
|
|
if !mb1.MatchFilter(mb2, "", false, false) {
|
|
t.Errorf("Match filter failure: %+v == %+v", mb1, mb2)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchFilterDiffId(t *testing.T) {
|
|
mb1 := &Balance{ID: "T1", Weight: 1, precision: 1, RatingSubject: "1", DestinationIDs: utils.StringMap{}}
|
|
mb2 := &BalanceFilter{ID: utils.StringPointer("T2"), Weight: utils.Float64Pointer(1), RatingSubject: utils.StringPointer("1"), DestinationIDs: nil}
|
|
if mb1.MatchFilter(mb2, "", false, false) {
|
|
t.Errorf("Match filter failure: %+v != %+v", mb1, mb2)
|
|
}
|
|
}
|
|
|
|
func TestBalanceClone(t *testing.T) {
|
|
var mb1 *Balance
|
|
if mb2 := mb1.Clone(); mb2 != nil {
|
|
t.Errorf("Balance should be %v", mb2)
|
|
}
|
|
|
|
mb1 = &Balance{Value: 1, Weight: 2, RatingSubject: "test", DestinationIDs: utils.NewStringMap("5")}
|
|
mb2 := mb1.Clone()
|
|
if mb1 == mb2 || !mb1.Equal(mb2) {
|
|
t.Errorf("Cloning failure: \n%+v\n%+v", mb1, mb2)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchActionTriggerId(t *testing.T) {
|
|
at := &ActionTrigger{Balance: &BalanceFilter{ID: utils.StringPointer("test")}}
|
|
b := &Balance{ID: "test"}
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.ID = "test1"
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.ID = ""
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.ID = "test"
|
|
at.Balance.ID = nil
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchActionTriggerDestination(t *testing.T) {
|
|
at := &ActionTrigger{Balance: &BalanceFilter{DestinationIDs: utils.StringMapPointer(utils.NewStringMap("test"))}}
|
|
b := &Balance{DestinationIDs: utils.NewStringMap("test")}
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.DestinationIDs = utils.NewStringMap("test1")
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.DestinationIDs = utils.NewStringMap("")
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.DestinationIDs = utils.NewStringMap("test")
|
|
at.Balance.DestinationIDs = nil
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchActionTriggerWeight(t *testing.T) {
|
|
at := &ActionTrigger{Balance: &BalanceFilter{Weight: utils.Float64Pointer(1)}}
|
|
b := &Balance{Weight: 1}
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.Weight = 2
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.Weight = 0
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.Weight = 1
|
|
at.Balance.Weight = nil
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchActionTriggerRatingSubject(t *testing.T) {
|
|
|
|
at := &ActionTrigger{Balance: &BalanceFilter{RatingSubject: utils.StringPointer("test")}}
|
|
b := &Balance{RatingSubject: "test"}
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.RatingSubject = "test1"
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.RatingSubject = ""
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.RatingSubject = "test"
|
|
at.Balance.RatingSubject = nil
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
}
|
|
|
|
func TestBalanceMatchActionTriggerSharedGroup(t *testing.T) {
|
|
at := &ActionTrigger{Balance: &BalanceFilter{SharedGroups: utils.StringMapPointer(utils.NewStringMap("test"))}}
|
|
b := &Balance{SharedGroups: utils.NewStringMap("test")}
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.SharedGroups = utils.NewStringMap("test1")
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.SharedGroups = utils.NewStringMap("")
|
|
if b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
b.SharedGroups = utils.NewStringMap("test")
|
|
at.Balance.SharedGroups = nil
|
|
if !b.MatchActionTrigger(at) {
|
|
t.Errorf("Error matching action trigger: %+v %+v", b, at)
|
|
}
|
|
}
|
|
|
|
func TestBalanceIsDefault(t *testing.T) {
|
|
b := &Balance{Weight: 0}
|
|
if b.IsDefault() {
|
|
t.Errorf("Balance should not be default: %+v", b)
|
|
}
|
|
b = &Balance{ID: utils.MetaDefault}
|
|
if !b.IsDefault() {
|
|
t.Errorf("Balance should be default: %+v", b)
|
|
}
|
|
}
|
|
|
|
func TestBalanceIsExpiredAt(t *testing.T) {
|
|
//expiration date is 0
|
|
balance := &Balance{}
|
|
var date2 time.Time
|
|
if rcv := balance.IsExpiredAt(date2); rcv {
|
|
t.Errorf("Expecting: false , received: %+v", rcv)
|
|
}
|
|
//expiration date before time t
|
|
balance.ExpirationDate = time.Date(2020, time.April, 18, 23, 0, 3, 0, time.UTC)
|
|
date2 = time.Date(2020, time.April, 18, 23, 0, 4, 0, time.UTC)
|
|
if rcv := balance.IsExpiredAt(date2); !rcv {
|
|
t.Errorf("Expecting: true , received: %+v", rcv)
|
|
}
|
|
//expiration date after time t
|
|
date2 = time.Date(2020, time.April, 18, 23, 0, 2, 0, time.UTC)
|
|
if rcv := balance.IsExpiredAt(date2); rcv {
|
|
t.Errorf("Expecting: false , received: %+v", rcv)
|
|
}
|
|
//time t = 0
|
|
var date3 time.Time
|
|
if rcv := balance.IsExpiredAt(date3); rcv {
|
|
t.Errorf("Expecting: false , received: %+v", rcv)
|
|
}
|
|
|
|
}
|
|
|
|
func TestBalanceAsInterface(t *testing.T) {
|
|
|
|
b := &Balance{
|
|
Uuid: "uuid",
|
|
ID: "id",
|
|
Value: 2.21,
|
|
ExpirationDate: time.Date(2022, 11, 22, 9, 0, 0, 0, time.UTC),
|
|
Weight: 2.88,
|
|
DestinationIDs: utils.StringMap{
|
|
"destId1": true,
|
|
"destId2": true,
|
|
},
|
|
RatingSubject: "rating",
|
|
Categories: utils.StringMap{
|
|
"ctg1": true,
|
|
"ctg2": false,
|
|
},
|
|
SharedGroups: utils.StringMap{
|
|
"shgp1": false,
|
|
"shgp2": true,
|
|
},
|
|
Timings: []*RITiming{
|
|
{
|
|
ID: "id",
|
|
Years: utils.Years{2, 3},
|
|
},
|
|
},
|
|
TimingIDs: utils.StringMap{
|
|
"timingid1": true,
|
|
"timingid2": false,
|
|
},
|
|
Factors: ValueFactors{
|
|
"factor1": 2.21,
|
|
"factor2": 1.34,
|
|
},
|
|
}
|
|
|
|
if _, err := b.FieldAsInterface([]string{}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"value"}); err == nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"DestinationIDs[destId1]", "secondVal"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Categories[ctg1]", "secondVal"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"SharedGroups[shgp1]", "secondVal"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"TimingIDs[timingid1]", "secondVal"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Timings[zero]"}); err == nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Timings[2]"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Timings[2]", "val"}); err == nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Factors[factor1]", "secondVal"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
}
|
|
|
|
if _, err = b.FieldAsInterface([]string{"DestinationIDs[destId1]"}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Categories[ctg1]"}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"SharedGroups[shgp1]"}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"TimingIDs[timingid1]"}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Timings[0]"}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{"Factors[factor1]"}); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if _, err = b.FieldAsInterface([]string{utils.Uuid}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.ExpirationDate}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Weight}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.DestinationIDs}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.DestinationIDs}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.RatingSubject}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Categories}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.SharedGroups}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Timings}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Disabled}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Factors}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Blocker}); err != nil {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.TimingIDs}); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if _, err = b.FieldAsInterface([]string{utils.TimingIDs, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Uuid, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.ID, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Value, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.ExpirationDate, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Weight, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.DestinationIDs, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.RatingSubject, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.Categories, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = b.FieldAsInterface([]string{utils.SharedGroups, "val"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestValueFactorsFieldAsInterface(t *testing.T) {
|
|
v := &ValueFactors{
|
|
"FACT_VAL": 20.22,
|
|
}
|
|
if _, err := v.FieldAsInterface([]string{}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = v.FieldAsInterface([]string{"TEST"}); err == nil || err != utils.ErrNotFound {
|
|
t.Error(err)
|
|
} else if _, err = v.FieldAsInterface([]string{"FACT_VAL"}); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
func TestValueFactorFieldAsString(t *testing.T) {
|
|
v := &ValueFactors{
|
|
"FACT_VAL": 20.22,
|
|
}
|
|
if _, err = v.FieldAsString([]string{"TEST"}); err == nil {
|
|
t.Error(err)
|
|
} else if _, err = v.FieldAsString([]string{"FACT_VAL"}); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestBalancesHasBalance(t *testing.T) {
|
|
bc := Balances{
|
|
{
|
|
Uuid: "uuid",
|
|
ID: "id",
|
|
Value: 12.22,
|
|
ExpirationDate: time.Date(2022, 11, 1, 20, 0, 0, 0, time.UTC),
|
|
Blocker: true,
|
|
Disabled: true,
|
|
precision: 2,
|
|
},
|
|
{
|
|
Uuid: "uuid2",
|
|
ID: "id2",
|
|
Value: 133.22,
|
|
ExpirationDate: time.Date(2023, 3, 21, 5, 0, 0, 0, time.UTC),
|
|
Blocker: true,
|
|
Disabled: true,
|
|
precision: 2,
|
|
},
|
|
}
|
|
balance := &Balance{
|
|
Uuid: "uuid",
|
|
ID: "id",
|
|
Value: 12.22,
|
|
ExpirationDate: time.Date(2022, 11, 1, 20, 0, 0, 0, time.UTC),
|
|
Blocker: true,
|
|
Disabled: true,
|
|
precision: 2,
|
|
}
|
|
|
|
if !bc.HasBalance(balance) {
|
|
t.Error("should be true")
|
|
}
|
|
|
|
}
|
|
|
|
func TestGetMinutesForCredi(t *testing.T) {
|
|
utils.Logger.SetLogLevel(4)
|
|
utils.Logger.SetSyslog(nil)
|
|
buf := new(bytes.Buffer)
|
|
log.SetOutput(buf)
|
|
defer func() {
|
|
utils.Logger.SetLogLevel(0)
|
|
log.SetOutput(os.Stderr)
|
|
}()
|
|
b := &Balance{
|
|
Value: 20 * float64(time.Second),
|
|
DestinationIDs: utils.NewStringMap("NAT"),
|
|
Weight: 10, RatingSubject: "rif",
|
|
}
|
|
cd := &CallDescriptor{
|
|
Category: "postpaid",
|
|
ToR: utils.MetaVoice,
|
|
Tenant: "foehn",
|
|
Subject: "foehn",
|
|
Account: "foehn",
|
|
Destination: "0034678096720",
|
|
TimeStart: time.Date(2015, 4, 24, 7, 59, 4, 0, time.UTC),
|
|
TimeEnd: time.Date(2015, 4, 24, 8, 2, 0, 0, time.UTC),
|
|
LoopIndex: 0,
|
|
DurationIndex: 176 * time.Second,
|
|
}
|
|
if dur, _ := b.GetMinutesForCredit(cd, 12); dur != 0 {
|
|
t.Error(err)
|
|
}
|
|
expLog := `Error getting new cost for balance subject:`
|
|
if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) {
|
|
t.Errorf("expected %v,received %v", utils.ToJSON(expLog), utils.ToJSON(rcvLog))
|
|
}
|
|
}
|
|
|
|
func TestBalancesStringValFactors(t *testing.T) {
|
|
factors := ValueFactors{
|
|
"factor1": 10.5,
|
|
"factor2": 20.3,
|
|
}
|
|
jsonString := factors.String()
|
|
if jsonString == "" {
|
|
t.Errorf("String(): expected non-empty JSON string, got empty")
|
|
}
|
|
}
|
|
|
|
func TestBalancesHasDestination(t *testing.T) {
|
|
balance := &Balance{
|
|
DestinationIDs: utils.StringMap{
|
|
"destination1": true,
|
|
"destination2": false,
|
|
},
|
|
}
|
|
hasDest := balance.HasDestination()
|
|
expected := true
|
|
if hasDest != expected {
|
|
t.Errorf("HasDestination(): expected %t, got %t", expected, hasDest)
|
|
}
|
|
balanceEmpty := &Balance{
|
|
DestinationIDs: utils.StringMap{},
|
|
}
|
|
hasDestEmpty := balanceEmpty.HasDestination()
|
|
expectedEmpty := false
|
|
if hasDestEmpty != expectedEmpty {
|
|
t.Errorf("HasDestination(): expected %t, got %t for empty DestinationIDs map", expectedEmpty, hasDestEmpty)
|
|
}
|
|
}
|
|
|
|
func TestBalancesMatchDestination(t *testing.T) {
|
|
balanceWithDestinations := &Balance{
|
|
DestinationIDs: utils.StringMap{
|
|
"destination1": true,
|
|
"destination2": false,
|
|
},
|
|
}
|
|
if !balanceWithDestinations.MatchDestination("destination1") {
|
|
t.Errorf("MatchDestination(destination1): expected true, got false")
|
|
}
|
|
if balanceWithDestinations.MatchDestination("destination2") {
|
|
t.Errorf("MatchDestination(destination2): expected false, got true")
|
|
}
|
|
if balanceWithDestinations.MatchDestination("nonexistent") {
|
|
t.Errorf("MatchDestination(nonexistent): expected false, got true")
|
|
}
|
|
balanceNoDestinations := &Balance{
|
|
DestinationIDs: utils.StringMap{},
|
|
}
|
|
if !balanceNoDestinations.MatchDestination("anydestination") {
|
|
t.Errorf("MatchDestination(anydestination): expected true, got false for empty DestinationIDs map")
|
|
}
|
|
}
|
|
|
|
func TestBalancesSetInitialValue(t *testing.T) {
|
|
t.Run("OldNotNull", func(t *testing.T) {
|
|
as := &AccountSummary{
|
|
BalanceSummaries: BalanceSummaries{
|
|
{UUID: "1", Value: 100, Initial: 0},
|
|
{UUID: "2", Value: 200, Initial: 0},
|
|
},
|
|
}
|
|
old := &AccountSummary{
|
|
BalanceSummaries: BalanceSummaries{
|
|
{UUID: "1", Value: 50, Initial: 0},
|
|
{UUID: "3", Value: 300, Initial: 0},
|
|
},
|
|
}
|
|
as.SetInitialValue(old)
|
|
expected := &AccountSummary{
|
|
BalanceSummaries: BalanceSummaries{
|
|
{UUID: "1", Value: 100, Initial: 50},
|
|
{UUID: "2", Value: 200, Initial: 0},
|
|
{UUID: "3", Value: 0, Initial: 0},
|
|
},
|
|
}
|
|
if diff := cmp.Diff(as, expected); diff != "" {
|
|
t.Errorf("Unexpected result (-got +want):\n%s", diff)
|
|
}
|
|
})
|
|
t.Run("OldNull", func(t *testing.T) {
|
|
as := &AccountSummary{
|
|
BalanceSummaries: BalanceSummaries{
|
|
{UUID: "1", Value: 100, Initial: 0},
|
|
{UUID: "2", Value: 200, Initial: 0},
|
|
},
|
|
}
|
|
as.SetInitialValue(nil)
|
|
expected := &AccountSummary{
|
|
BalanceSummaries: BalanceSummaries{
|
|
{UUID: "1", Value: 100, Initial: 0},
|
|
{UUID: "2", Value: 200, Initial: 0},
|
|
},
|
|
}
|
|
|
|
if diff := cmp.Diff(as, expected); diff != "" {
|
|
t.Errorf("Unexpected result (-got +want):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestBalancesValueFactorsGetValue(t *testing.T) {
|
|
testCases := []struct {
|
|
factors ValueFactors
|
|
category string
|
|
expected float64
|
|
}{
|
|
{
|
|
factors: nil,
|
|
category: "category1",
|
|
expected: 1.0,
|
|
},
|
|
{
|
|
factors: ValueFactors{"category2": 2.0, "category3": 3.0},
|
|
category: "category1",
|
|
expected: 1.0,
|
|
},
|
|
{
|
|
factors: ValueFactors{"category1": 1.5, "category2": 2.0, "category3": 3.0},
|
|
category: "category1",
|
|
expected: 1.5,
|
|
},
|
|
{
|
|
factors: ValueFactors{"category1": 0.0, "category2": 2.0, "category3": 3.0},
|
|
category: "category1",
|
|
expected: 0.0,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
result := tc.factors.GetValue(tc.category)
|
|
if result != tc.expected {
|
|
t.Errorf("Test failed for category '%s': expected %.2f, got %.2f", tc.category, tc.expected, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBalancesStringJson(t *testing.T) {
|
|
balances := Balances{
|
|
&Balance{
|
|
Uuid: "uuid123",
|
|
ID: "balance123",
|
|
Value: 100.0,
|
|
ExpirationDate: time.Date(2024, time.December, 31, 23, 59, 59, 0, time.UTC),
|
|
Weight: 1.5,
|
|
DestinationIDs: utils.StringMap{},
|
|
RatingSubject: "ratingSub",
|
|
Categories: utils.StringMap{},
|
|
SharedGroups: utils.StringMap{},
|
|
Timings: []*RITiming{},
|
|
TimingIDs: utils.StringMap{},
|
|
Disabled: false,
|
|
Blocker: true,
|
|
precision: 2,
|
|
account: nil,
|
|
dirty: false,
|
|
},
|
|
}
|
|
|
|
result := balances.String()
|
|
if result == "" {
|
|
t.Error("Expected non-empty JSON string, but got empty string")
|
|
}
|
|
}
|
|
|
|
func TestBalanceFieldAsString(t *testing.T) {
|
|
balance := &Balance{
|
|
Uuid: "uuid123",
|
|
}
|
|
val, err := balance.FieldAsString([]string{"Uuid"})
|
|
if err != nil {
|
|
t.Errorf("Unexpected error for field 'Uuid': %v", err)
|
|
}
|
|
expected := balance.Uuid
|
|
if val != expected {
|
|
t.Errorf("Expected value '%s' for field 'Uuid', but got '%s'", expected, val)
|
|
}
|
|
_, err = balance.FieldAsString([]string{"InvalidField"})
|
|
if err == nil {
|
|
t.Error("Expected error for invalid field path, but got nil")
|
|
}
|
|
}
|
|
|
|
func TestBalancesString(t *testing.T) {
|
|
balance := &Balance{
|
|
Uuid: "123e4567-e89b-12d3-a456-426614174000",
|
|
}
|
|
jsonStr := balance.String()
|
|
var data map[string]interface{}
|
|
err := json.Unmarshal([]byte(jsonStr), &data)
|
|
if err != nil {
|
|
t.Errorf("Error unmarshalling JSON string: %v", err)
|
|
}
|
|
expectedUuid := balance.Uuid
|
|
if uuid, ok := data["Uuid"].(string); !ok || uuid != expectedUuid {
|
|
t.Errorf("Expected Uuid '%s' in JSON, but got '%v'", expectedUuid, data["Uuid"])
|
|
}
|
|
}
|
|
func TestBalancesHasBalanceReturn(t *testing.T) {
|
|
balances := Balances{
|
|
{ID: "1"},
|
|
{ID: "2"},
|
|
{ID: "3"},
|
|
}
|
|
existingBalance := &Balance{ID: "2"}
|
|
if !balances.HasBalance(existingBalance) {
|
|
t.Errorf("Expected balance with ID '%s' to exist, but it does not", existingBalance.ID)
|
|
}
|
|
nonExistingBalance := &Balance{ID: "4"}
|
|
if balances.HasBalance(nonExistingBalance) {
|
|
t.Errorf("Expected balance with ID '%s' to not exist, but it does", nonExistingBalance.ID)
|
|
}
|
|
}
|
|
|
|
func TestBalancesEqual(t *testing.T) {
|
|
balances1 := Balances{
|
|
{ID: "1"},
|
|
{ID: "2"},
|
|
{ID: "3"},
|
|
}
|
|
balances2 := Balances{
|
|
{ID: "1"},
|
|
{ID: "2"},
|
|
{ID: "3"},
|
|
}
|
|
if !balances1.Equal(balances1) {
|
|
t.Errorf("Expected balances1 to equal itself, but it does not")
|
|
}
|
|
if !balances1.Equal(balances2) {
|
|
t.Errorf("Expected balances1 to equal balances2, but they are not equal")
|
|
}
|
|
balances3 := Balances{
|
|
{ID: "1"},
|
|
{ID: "2"},
|
|
}
|
|
if balances1.Equal(balances3) {
|
|
t.Errorf("Expected balances1 to not equal balances3, but they are equal")
|
|
}
|
|
balances4 := Balances{
|
|
{ID: "1"},
|
|
{ID: "2"},
|
|
{ID: "4"},
|
|
}
|
|
if balances1.Equal(balances4) {
|
|
t.Errorf("Expected balances1 to not equal balances4, but they are equal")
|
|
}
|
|
}
|
|
|
|
func TestBalancesFieldAsString(t *testing.T) {
|
|
bc := Balances{
|
|
&Balance{
|
|
Uuid: "uuid123",
|
|
ID: "balance123",
|
|
Value: 100.0,
|
|
ExpirationDate: time.Date(2024, time.December, 31, 23, 59, 59, 0, time.UTC),
|
|
Weight: 1.5,
|
|
DestinationIDs: utils.StringMap{},
|
|
RatingSubject: "ratingSub",
|
|
Categories: utils.StringMap{},
|
|
SharedGroups: utils.StringMap{},
|
|
Timings: []*RITiming{},
|
|
TimingIDs: utils.StringMap{},
|
|
Disabled: false,
|
|
Blocker: true,
|
|
precision: 2,
|
|
account: nil,
|
|
dirty: false,
|
|
},
|
|
}
|
|
|
|
t.Run("empty field path", func(t *testing.T) {
|
|
val, err := bc.FieldAsString([]string{})
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if val != "" {
|
|
t.Errorf("expected empty string, got '%v'", val)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid field path", func(t *testing.T) {
|
|
val, err := bc.FieldAsString([]string{"invalid"})
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if val != "" {
|
|
t.Errorf("expected empty string, got '%v'", val)
|
|
}
|
|
})
|
|
|
|
t.Run("valid field path for non-existing ID", func(t *testing.T) {
|
|
val, err := bc.FieldAsString([]string{"2", "ID"})
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if val != "" {
|
|
t.Errorf("expected empty string, got '%v'", val)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestBalancesIsActiveAt(t *testing.T) {
|
|
testTime := time.Now()
|
|
|
|
t.Run("balance is disabled", func(t *testing.T) {
|
|
balance := &Balance{
|
|
Disabled: true,
|
|
}
|
|
if balance.IsActiveAt(testTime) {
|
|
t.Errorf("expected false, got true")
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
func TestBalancesFieldAsInterfaceIndexPath(t *testing.T) {
|
|
|
|
bc := Balances{
|
|
&Balance{
|
|
Uuid: "uuid123",
|
|
ID: "balance123",
|
|
Value: 100.0,
|
|
ExpirationDate: time.Date(2024, time.December, 31, 23, 59, 59, 0, time.UTC),
|
|
Weight: 1.5,
|
|
DestinationIDs: utils.StringMap{},
|
|
RatingSubject: "ratingSub",
|
|
Categories: utils.StringMap{},
|
|
SharedGroups: utils.StringMap{},
|
|
Timings: []*RITiming{},
|
|
TimingIDs: utils.StringMap{},
|
|
Disabled: false,
|
|
Blocker: true,
|
|
precision: 2,
|
|
account: nil,
|
|
dirty: false,
|
|
},
|
|
}
|
|
|
|
t.Run("test index path in FieldAsInterface", func(t *testing.T) {
|
|
|
|
idx := "0"
|
|
val, err := bc.FieldAsInterface([]string{idx})
|
|
|
|
if err != nil {
|
|
t.Errorf("expected no error, got %v", err)
|
|
}
|
|
|
|
expected := bc[0]
|
|
if val != expected {
|
|
t.Errorf("expected '%v', got '%v'", expected, val)
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
func TestBalanceSummaryFieldAsInterfaceUnsupportedField(t *testing.T) {
|
|
balanceSummary := &BalanceSummary{}
|
|
fldPath := []string{"unsupportedField"}
|
|
expectedError := fmt.Sprintf("unsupported field prefix: <%s>", fldPath[0])
|
|
_, err := balanceSummary.FieldAsInterface(fldPath)
|
|
if err == nil {
|
|
t.Fatalf("Expected an error but got nil")
|
|
}
|
|
if err.Error() != expectedError {
|
|
t.Errorf("Expected error: %s, but got: %s", expectedError, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestBalancesSummaryFieldAsInterface(t *testing.T) {
|
|
var balanceSummary *BalanceSummary
|
|
fldPath := []string{"Filed"}
|
|
_, err := balanceSummary.FieldAsInterface(fldPath)
|
|
if err != utils.ErrNotFound {
|
|
t.Fatalf("Expected utils.ErrNotFound but got: %v", err)
|
|
}
|
|
balanceSummary = &BalanceSummary{}
|
|
fldPath = []string{}
|
|
_, err = balanceSummary.FieldAsInterface(fldPath)
|
|
if err != utils.ErrNotFound {
|
|
t.Fatalf("Expected utils.ErrNotFound but got: %v", err)
|
|
}
|
|
fldPath = []string{"unsupportedField"}
|
|
expectedError := fmt.Sprintf("unsupported field prefix: <%s>", fldPath[0])
|
|
_, err = balanceSummary.FieldAsInterface(fldPath)
|
|
if err == nil {
|
|
t.Fatalf("Expected an error but got nil")
|
|
}
|
|
if err.Error() != expectedError {
|
|
t.Errorf("Expected error: %s, but got: %s", expectedError, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestBalancesHardMatchFilterNilFilter(t *testing.T) {
|
|
balance := &Balance{}
|
|
var balanceFilter *BalanceFilter = nil
|
|
result := balance.HardMatchFilter(balanceFilter, false)
|
|
if result != true {
|
|
t.Errorf("Expected true when balanceFilter is nil, but got %v", result)
|
|
}
|
|
}
|
|
|
|
func TestBalancesHardMatchFilter(t *testing.T) {
|
|
t.Run("NilFilter", func(t *testing.T) {
|
|
balance := &Balance{}
|
|
var balanceFilter *BalanceFilter = nil
|
|
|
|
result := balance.HardMatchFilter(balanceFilter, false)
|
|
if result != true {
|
|
t.Errorf("Expected true when balanceFilter is nil, but got %v", result)
|
|
}
|
|
})
|
|
t.Run("UuidMatch", func(t *testing.T) {
|
|
expectedUuid := "1"
|
|
balance := &Balance{Uuid: expectedUuid}
|
|
balanceFilter := &BalanceFilter{Uuid: &expectedUuid}
|
|
|
|
result := balance.HardMatchFilter(balanceFilter, false)
|
|
if result != true {
|
|
t.Errorf("Expected true when Uuid matches, but got %v", result)
|
|
}
|
|
})
|
|
t.Run("UuidNoMatch", func(t *testing.T) {
|
|
balance := &Balance{Uuid: "1"}
|
|
nonMatchingUuid := "2"
|
|
balanceFilter := &BalanceFilter{Uuid: &nonMatchingUuid}
|
|
|
|
result := balance.HardMatchFilter(balanceFilter, false)
|
|
if result != false {
|
|
t.Errorf("Expected false when Uuid doesn't match, but got %v", result)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFieldAsStringCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
balance Balance
|
|
fldPath []string
|
|
expected string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "ID field",
|
|
balance: Balance{ID: "test-id", Value: 10.5},
|
|
fldPath: []string{"ID"},
|
|
expected: "test-id",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Value field",
|
|
balance: Balance{ID: "test-id", Value: 10.5},
|
|
fldPath: []string{"Value"},
|
|
expected: "10.5",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Non-existent field",
|
|
balance: Balance{ID: "test-id", Value: 10.5},
|
|
fldPath: []string{"NonExistent"},
|
|
expected: "",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.balance.FieldAsString(tt.fldPath)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("FieldAsString() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.expected {
|
|
t.Errorf("FieldAsString() = %v, want %v", got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
balance Balance
|
|
expected string
|
|
}{
|
|
{
|
|
name: "Default case",
|
|
balance: Balance{
|
|
ID: "test-id",
|
|
Value: 10.5,
|
|
},
|
|
expected: `{"Uuid":"","ID":"test-id","Value":10.5,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":0,"DestinationIDs":null,"RatingSubject":"","Categories":null,"SharedGroups":null,"Timings":null,"TimingIDs":null,"Disabled":false,"Factors":null,"Blocker":false}`,
|
|
},
|
|
{
|
|
name: "Zero value case",
|
|
balance: Balance{},
|
|
expected: `{"Uuid":"","ID":"","Value":0,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":0,"DestinationIDs":null,"RatingSubject":"","Categories":null,"SharedGroups":null,"Timings":null,"TimingIDs":null,"Disabled":false,"Factors":null,"Blocker":false}`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.balance.String()
|
|
if got != tt.expected {
|
|
t.Errorf("String() = %v, want %v", got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFieldAsStringCase(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
balances Balances
|
|
fldPath []string
|
|
expected string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Invalid field path",
|
|
balances: Balances{{ID: "test-id", Value: 10.5}},
|
|
fldPath: []string{"NonExistentField"},
|
|
expected: "",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Empty field path",
|
|
balances: Balances{{ID: "test-id", Value: 10.5}},
|
|
fldPath: []string{},
|
|
expected: "",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.balances.FieldAsString(tt.fldPath)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("FieldAsString() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.expected {
|
|
t.Errorf("FieldAsString() = %v, want %v", got, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|