diff --git a/engine/account_test.go b/engine/account_test.go index 4eedb550f..98bc5146d 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -18,6 +18,7 @@ along with this program. If not, see package engine import ( + "encoding/json" "reflect" "testing" "time" @@ -2858,3 +2859,551 @@ func BenchmarkGetSecondsForPrefix(b *testing.B) { ub1.getCreditForPrefix(cd) } } + +var bl bool = true +var str2 string = "test" +var fl2 float64 = 1.2 +var nm2 int = 1 +var tm2 time.Time = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC) + +func TestAccountsetBalanceAction(t *testing.T) { + var acc *Account + + err := acc.setBalanceAction(nil) + + if err != nil { + if err.Error() != "nil action" { + t.Error(err) + } + } + + sm := utils.StringMap{str: bl} + rtm := RITiming{ + Years: utils.Years{2021}, + Months: utils.Months{8}, + MonthDays: utils.MonthDays{28}, + WeekDays: utils.WeekDays{5}, + StartTime: str2, + EndTime: str2, + cronString: str2, + tag: str2, + } + vf := ValueFactor{str2: fl2} + vfr := utils.ValueFormula{ + Method: str2, + Params: map[string]any{str2: str2}, + Static: fl2, + } + bf := BalanceFilter{ + Uuid: &str2, + ID: &str2, + Type: &str2, + Value: &vfr, + ExpirationDate: &tm2, + Weight: &fl2, + DestinationIDs: &sm, + RatingSubject: &str2, + Categories: &sm, + SharedGroups: &sm, + TimingIDs: &sm, + Timings: []*RITiming{&rtm}, + Disabled: &bl, + Factor: &vf, + Blocker: &bl, + } + cf := CounterFilter{ + Value: fl, + Filter: &bf, + } + uc := UnitCounter{ + CounterType: "*balance", + Counters: CounterFilters{&cf}, + } + at := ActionTrigger{ + ID: str2, + UniqueID: str2, + ThresholdType: str2, + Recurrent: bl, + MinSleep: 1 * time.Millisecond, + ExpirationDate: tm2, + ActivationDate: tm2, + Balance: &bf, + Weight: fl2, + ActionsID: str2, + MinQueuedItems: nm2, + Executed: bl, + LastExecutionTime: tm2, + } + + ac := Account{ + ID: str2, + UnitCounters: UnitCounters{str: {&uc}}, + ActionTriggers: ActionTriggers{&at}, + AllowNegative: bl, + Disabled: bl, + UpdateTime: tm2, + executingTriggers: bl, + } + a := Action{ + Id: str2, + ActionType: str2, + ExtraParameters: str2, + Filter: str2, + ExpirationString: str2, + Weight: fl2, + Balance: &bf, + balanceValue: fl2, + } + + err = ac.setBalanceAction(&a) + + if err != nil { + if err.Error() != "cannot find balance with uuid: " { + t.Error(err) + } + } +} + +func TestAccountGetSharedGroups(t *testing.T) { + sm := utils.StringMap{ + "test1": bl, + } + rtm := RITiming{ + Years: utils.Years{2021}, + Months: utils.Months{8}, + MonthDays: utils.MonthDays{28}, + WeekDays: utils.WeekDays{5}, + StartTime: str, + EndTime: str, + cronString: str, + tag: str, + } + vf := ValueFactor{str: fl} + vfr := utils.ValueFormula{ + Method: str, + Params: map[string]any{str: str}, + Static: fl, + } + bf := BalanceFilter{ + Uuid: &str, + ID: &str, + Type: &str, + Value: &vfr, + ExpirationDate: &tm, + Weight: &fl, + DestinationIDs: &sm, + RatingSubject: &str, + Categories: &sm, + SharedGroups: &sm, + TimingIDs: &sm, + Timings: []*RITiming{&rtm}, + Disabled: &bl, + Factor: &vf, + Blocker: &bl, + } + cf := CounterFilter{ + Value: fl, + Filter: &bf, + } + uc := UnitCounter{ + CounterType: "*balance", + Counters: CounterFilters{&cf}, + } + at := ActionTrigger{ + ID: str, + UniqueID: str, + ThresholdType: str, + Recurrent: bl, + MinSleep: 1 * time.Millisecond, + ExpirationDate: tm, + ActivationDate: tm, + Balance: &bf, + Weight: fl, + ActionsID: str, + MinQueuedItems: nm, + Executed: bl, + LastExecutionTime: tm, + } + + blc := Balance{ + Uuid: str2, + ID: str2, + Value: fl2, + ExpirationDate: tm2, + Weight: fl2, + DestinationIDs: sm, + RatingSubject: str2, + Categories: sm, + SharedGroups: sm, + Timings: []*RITiming{&rtm}, + TimingIDs: sm, + Disabled: bl, + Factor: ValueFactor{str2: fl2}, + Blocker: bl, + precision: nm2, + dirty: bl, + } + ac := Account{ + ID: str, + BalanceMap: map[string]Balances{str: {&blc}}, + UnitCounters: UnitCounters{str: {&uc}}, + ActionTriggers: ActionTriggers{&at}, + AllowNegative: bl, + Disabled: bl, + UpdateTime: tm, + executingTriggers: bl, + } + + rcv := ac.GetSharedGroups() + exp := []string{"test1"} + if !reflect.DeepEqual(rcv, exp) { + t.Errorf("expected %v, received %v", exp, rcv) + } +} + +func TestAccountSummaryFieldAsInterface(t *testing.T) { + bs := BalanceSummary{ + UUID: str2, + ID: str2, + Type: str2, + Value: fl2, + Disabled: bl, + } + as := AccountSummary{ + Tenant: str2, + ID: str2, + BalanceSummaries: BalanceSummaries{&bs}, + AllowNegative: bl, + Disabled: bl, + } + + type exp struct { + val any + err string + } + + tests := []struct { + name string + arg []string + exp exp + }{ + { + name: "empty field path", + arg: []string{}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "default case", + arg: []string{"BalanceSummaries[0]"}, + exp: exp{val: &bs, err: ""}, + }, + { + name: "unsupported field prefix", + arg: []string{"test"}, + exp: exp{val: nil, err: "unsupported field prefix: "}, + }, + { + name: "case Tenant not found", + arg: []string{"Tenant", "test"}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "case BalanceSummaries not found", + arg: []string{"BalanceSummaries", "test"}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "case AllowNegative not found", + arg: []string{"AllowNegative", "test"}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "case ID not found", + arg: []string{"ID", "test"}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "case Disabled not found", + arg: []string{"Disabled", "test"}, + exp: exp{val: nil, err: "NOT_FOUND"}, + }, + { + name: "case Tenant", + arg: []string{"Tenant"}, + exp: exp{val: str2, err: ""}, + }, + { + name: "case ID", + arg: []string{"ID"}, + exp: exp{val: str2, err: ""}, + }, + { + name: "case BalanceSummaries", + arg: []string{"BalanceSummaries"}, + exp: exp{val: BalanceSummaries{&bs}, err: ""}, + }, + { + name: "case AllowNegative", + arg: []string{"AllowNegative"}, + exp: exp{val: bl, err: ""}, + }, + { + name: "case Disabled", + arg: []string{"Disabled"}, + exp: exp{val: bl, err: ""}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rcv, err := as.FieldAsInterface(tt.arg) + + if err != nil { + if err.Error() != tt.exp.err { + t.Error(err) + } + } + + if !reflect.DeepEqual(rcv, tt.exp.val) { + t.Errorf("expected %v, received %v", tt.exp.val, rcv) + } + }) + } +} + +func TestAccountSummaryUpdateBalances(t *testing.T) { + bs := BalanceSummary{ + UUID: str2, + ID: str2, + Type: str2, + Value: fl2, + Disabled: bl, + } + as := AccountSummary{ + Tenant: str2, + ID: str2, + BalanceSummaries: BalanceSummaries{&bs}, + AllowNegative: bl, + Disabled: bl, + } + + exp := as + + as.UpdateBalances(nil) + + if !reflect.DeepEqual(as, exp) { + t.Error("Account summary was updated") + } +} + +func TestNewAccountSummaryFromJSON(t *testing.T) { + bs := BalanceSummary{ + UUID: str2, + ID: str2, + Type: str2, + Value: fl2, + Disabled: bl, + } + as := &AccountSummary{ + Tenant: str2, + ID: str2, + BalanceSummaries: BalanceSummaries{&bs}, + AllowNegative: bl, + Disabled: bl, + } + arg, errJ := json.Marshal(as) + if errJ != nil { + t.Error(errJ) + } + + rcv, err := NewAccountSummaryFromJSON(string(arg)) + if err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(rcv, as) { + t.Errorf("expected %v, received %v", as, rcv) + } +} + +func TestAsOldStructure(t *testing.T) { + sm := utils.StringMap{str: bl} + rtm := RITiming{ + Years: utils.Years{2021}, + Months: utils.Months{8}, + MonthDays: utils.MonthDays{28}, + WeekDays: utils.WeekDays{5}, + StartTime: str2, + EndTime: str2, + cronString: str2, + tag: str2, + } + vf := ValueFactor{str2: fl2} + vfr := utils.ValueFormula{ + Method: str2, + Params: map[string]any{str2: str2}, + Static: fl2, + } + bf := BalanceFilter{ + Uuid: &str2, + ID: &str2, + Type: &str2, + Value: &vfr, + ExpirationDate: &tm2, + Weight: &fl2, + DestinationIDs: &sm, + RatingSubject: &str2, + Categories: &sm, + SharedGroups: &sm, + TimingIDs: &sm, + Timings: []*RITiming{&rtm}, + Disabled: &bl, + Factor: &vf, + Blocker: &bl, + } + cf := CounterFilter{ + Value: fl, + Filter: &bf, + } + uc := UnitCounter{ + CounterType: "*balance", + Counters: CounterFilters{&cf}, + } + at := ActionTrigger{ + ID: str2, + UniqueID: str2, + ThresholdType: str2, + Recurrent: bl, + MinSleep: 1 * time.Millisecond, + ExpirationDate: tm2, + ActivationDate: tm2, + Balance: &bf, + Weight: fl2, + ActionsID: str2, + MinQueuedItems: nm2, + Executed: bl, + LastExecutionTime: tm2, + } + + blc := Balance{ + Uuid: str2, + ID: str2, + Value: fl2, + ExpirationDate: tm2, + Weight: fl2, + DestinationIDs: sm, + RatingSubject: str2, + Categories: sm, + SharedGroups: sm, + Timings: []*RITiming{&rtm}, + TimingIDs: sm, + Disabled: bl, + Factor: ValueFactor{str2: fl2}, + Blocker: bl, + precision: nm2, + dirty: bl, + } + acc := Account{ + ID: str2, + BalanceMap: map[string]Balances{str: {&blc}}, + UnitCounters: UnitCounters{str: {&uc, nil}}, + ActionTriggers: ActionTriggers{&at}, + AllowNegative: bl, + Disabled: bl, + UpdateTime: tm2, + executingTriggers: bl, + } + + type Balance struct { + Uuid string //system wide unique + Id string // account wide unique + Value float64 + ExpirationDate time.Time + Weight float64 + DestinationIds string + RatingSubject string + Category string + SharedGroup string + Timings []*RITiming + TimingIDs string + Disabled bool + precision int + account *Account + dirty bool + } + type Balances []*Balance + type UnitsCounter struct { + BalanceType string + // Units float64 + Balances Balances // first balance is the general one (no destination) + } + type ActionTrigger struct { + Id string + ThresholdType string + ThresholdValue float64 + Recurrent bool + MinSleep time.Duration + BalanceId string + BalanceType string + BalanceDestinationIds string + BalanceWeight float64 + BalanceExpirationDate time.Time + BalanceTimingTags string + BalanceRatingSubject string + BalanceCategory string + BalanceSharedGroup string + BalanceDisabled bool + Weight float64 + ActionsId string + MinQueuedItems int + Executed bool + } + type ActionTriggers []*ActionTrigger + + type Account struct { + Id string + BalanceMap map[string]Balances + UnitCounters []*UnitsCounter + ActionTriggers ActionTriggers + AllowNegative bool + Disabled bool + } + + rcv := acc.AsOldStructure() + + mrsh, err := json.Marshal(rcv) + if err != nil { + t.Error(err) + } + + var ac *Account + err = json.Unmarshal(mrsh, &ac) + if err != nil { + t.Error(err) + } + exp := utils.META_OUT + ":" + acc.ID + + if ac.Id != exp { + t.Errorf("expected %s, received %s", ac.Id, exp) + } + + if ac.AllowNegative != acc.AllowNegative { + t.Error(ac.AllowNegative) + } + + if ac.Disabled != acc.Disabled { + t.Error(ac.Disabled) + } +} + +func TestAccountGetID(t *testing.T) { + acc := Account{ + ID: str2, + } + + rcv := acc.GetID() + + if rcv != "" { + t.Error(rcv) + } +} \ No newline at end of file