/* 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 */ package utils import ( "math" "reflect" "testing" "time" "github.com/cgrates/cron" "github.com/ericlagergren/decimal" ) func TestLibratesTenantID(t *testing.T) { rp := &RateProfile{ Tenant: "tenant", ID: "testID", } expected := rp.Tenant + ":" + rp.ID received := rp.TenantID() if received != expected { t.Errorf("\nExpected: <%v>,\nReceived: <%v>", expected, received) } } func TestLibratesCompilerp(t *testing.T) { // empty struct rp := &RateProfile{} err := rp.Compile() if err != nil { t.Errorf("\nExpected: <%v>, \nReceived: <%v>", nil, err) } // non-empty fail := "shouldfail" rp.ID = "test" rp.Tenant = "tenant" rp.Rates = map[string]*Rate{ "testKey1": { ID: "ID1", ActivationTimes: fail, }, "testKey2": { ID: "ID2", }, } expected := "expected exactly 5 fields, found 1: [" + fail + "]" err = rp.Compile() if err == nil || err.Error() != expected { t.Errorf("\nExpected: <%v>, \nReceived: <%v>", expected, err) } } func TestLibratesUID(t *testing.T) { rt := &Rate{ uID: "testString", } expected := "testString" received := rt.UID() if received != expected { t.Errorf("\nExpected: %q, \nReceived: %q", expected, received) } } func TestLibratesCompilert(t *testing.T) { rt := &Rate{ ActivationTimes: EmptyString, } err := rt.Compile() if err != nil { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", nil, err) } } func TestLibratesRunTimes(t *testing.T) { var ( sTime time.Time eTime time.Time verbosity int ) // memory leak test verbosity = 0 rt := &Rate{} received, err := rt.RunTimes(sTime, eTime, verbosity) var expected [][]time.Time if err == nil || err != ErrMaxIterationsReached { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ErrMaxIterationsReached, err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } // aTime after eTime test schd, err := cron.ParseStandard("* * * * *") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } rt.sched = schd verbosity = 10 eTime = sTime.Add(10 * time.Minute) received, err = rt.RunTimes(sTime, eTime, verbosity) if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } // eTime before iTime test schd, err = cron.ParseStandard("* * 12 3 *") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } rt.sched = schd sTime, err = time.Parse(time.RFC3339, "2022-03-11T15:04:05Z") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } eTime = sTime.Add(24 * time.Hour) if received, err = rt.RunTimes(sTime, eTime, verbosity); err != nil { t.Error(err) } aT1, err := time.Parse(time.RFC3339, "2022-03-12T00:00:00Z") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } aT2, err := time.Parse(time.RFC3339, "2022-03-13T00:00:00Z") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } aTsl := make([]time.Time, 0) aTsl = append(aTsl, aT1, aT2) expected = append(expected, aTsl) if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } //eTime after iTime schd, err = cron.ParseStandard("* * 12 3 *") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } rt.sched = schd sTime, err = time.Parse(time.RFC3339, "2022-03-11T15:04:05Z") if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } eTime = sTime.Add(48 * time.Hour) received, err = rt.RunTimes(sTime, eTime, verbosity) if err != nil { t.Errorf("\ndidn't expect error, got %v", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } } func TestLibratesCorrectCost(t *testing.T) { //CorrectCost does nothing rPc := &RateProfileCost{ Cost: 1.234, MinCost: 1, MaxCost: 2, Altered: []string{}, } expected := &RateProfileCost{ Cost: 1.234, MinCost: 1, MaxCost: 2, Altered: []string{}, } rPc.CorrectCost(nil, "") if !reflect.DeepEqual(rPc, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) } //CorrectCost rounds the cost expected = &RateProfileCost{ Cost: 1.24, MinCost: 1, MaxCost: 2, Altered: []string{RoundingDecimals}, } rPc.CorrectCost(IntPointer(2), MetaRoundingUp) if !reflect.DeepEqual(rPc, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) } //CorrectCost assigns MaxCost to Cost when Cost > MaxCost expected = &RateProfileCost{ Cost: 2, MinCost: 1, MaxCost: 2, Altered: []string{RoundingDecimals, MaxCost}, } rPc.Cost = 2.34 rPc.CorrectCost(nil, "") if !reflect.DeepEqual(rPc, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) } //CorrectCost assigns MinCost to Cost when Cost < MinCost expected = &RateProfileCost{ Cost: 1, MinCost: 1, MaxCost: 2, Altered: []string{RoundingDecimals, MaxCost, MinCost}, } rPc.Cost = 0.12 rPc.CorrectCost(nil, "") if !reflect.DeepEqual(rPc, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) } } func TestRateProfileSort(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rPrf := &RateProfile{ Tenant: "cgrates.org", ID: "RP1", Rates: map[string]*Rate{ "RT_WEEK": { ID: "RT_WEEK", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 1-5", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_Custom": { ID: "RT_Custom", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 1-5", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(int64(time.Second), 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Second), 0), RecurrentFee: NewDecimal(19, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(15*time.Second), 0), RecurrentFee: NewDecimal(4, 1), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(10*time.Second), 0), RecurrentFee: NewDecimal(27, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_WEEKEND": { ID: "RT_WEEKEND", Weights: DynamicWeights{ { Weight: 10, }, }, ActivationTimes: "* * * * 0,6", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(int64(10*time.Second), 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(18, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(18*time.Second), 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_CHRISTMAS": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, }, } exp := &RateProfile{ Tenant: "cgrates.org", ID: "RP1", Rates: map[string]*Rate{ "RT_WEEK": { ID: "RT_WEEK", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 1-5", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_WEEKEND": { ID: "RT_WEEKEND", Weights: DynamicWeights{ { Weight: 10, }, }, ActivationTimes: "* * * * 0,6", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(int64(10*time.Second), 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(18*time.Second), 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(18, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_Custom": { ID: "RT_Custom", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 1-5", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(int64(time.Second), 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Second), 0), RecurrentFee: NewDecimal(19, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(10*time.Second), 0), RecurrentFee: NewDecimal(27, 2), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(15*time.Second), 0), RecurrentFee: NewDecimal(4, 1), Unit: minDecimal, Increment: secDecimal, }, }, }, "RT_CHRISTMAS": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(6, 2), Unit: minDecimal, Increment: secDecimal, }, }, }, }, } rPrf.Sort() if !reflect.DeepEqual(rPrf, exp) { t.Errorf("Expected: %v,\n received: %v", ToJSON(exp), ToJSON(rPrf)) } } func TestRateProfileCompile(t *testing.T) { rt := &RateProfile{ Rates: map[string]*Rate{ "randomVal1": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", }, }, Tenant: "cgrates.org", ID: "RTP1", } expectedATime, err := cron.ParseStandard("* * 24 12 *") if err != nil { t.Fatal(err) } expRt := &RateProfile{ Rates: map[string]*Rate{ "randomVal1": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", sched: expectedATime, uID: ConcatenatedKey(rt.Tenant, rt.ID, "RT_CHRISTMAS"), }, }, Tenant: "cgrates.org", ID: "RTP1", } if err := rt.Compile(); err != nil { t.Error(err) } else if !reflect.DeepEqual(rt, expRt) { t.Errorf("Expected %+v, received %+v", ToJSON(expRt), ToJSON(rt)) } } func TestRateUID(t *testing.T) { rt := &RateProfile{ Rates: map[string]*Rate{ "randomVal1": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", uID: "randomID", }, }, } expected := "randomID" if newID := rt.Rates["randomVal1"].UID(); !reflect.DeepEqual(newID, expected) { t.Errorf("Expected %+v, received %+v", expected, newID) } } func TestRateProfileCompileError(t *testing.T) { rt := &RateProfile{ Rates: map[string]*Rate{ "randomVal": { ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * * *", }, }, } expectedErr := "expected exactly 5 fields, found 4: [* * * *]" if err := rt.Compile(); err == nil || err.Error() != expectedErr { t.Errorf("Expected %+v, received %+v ", expectedErr, err) } } func TestRateCompileChristmasTime(t *testing.T) { rt := &Rate{ ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", } expTime, err := cron.ParseStandard("* * 24 12 *") if err != nil { t.Error(err) } expectedRt := &Rate{ ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", sched: expTime, } if err := rt.Compile(); err != nil { t.Error(err) } else if !reflect.DeepEqual(expectedRt, rt) { t.Errorf("Expected %+v, received %+v", expectedRt, rt) } } func TestRateCompileEmptyActivationTime(t *testing.T) { rt := &Rate{ ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: EmptyString, } expTime, err := cron.ParseStandard("* * * * *") if err != nil { t.Error(err) } expectedRt := &Rate{ ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: EmptyString, sched: expTime, } if err := rt.Compile(); err != nil { t.Error(err) } else if !reflect.DeepEqual(rt, expectedRt) { t.Errorf("Expected %+v, received %+v", expectedRt, rt) } } func TestRateProfileRunTimes(t *testing.T) { rt := &Rate{ ID: "RATE0", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), }, }, } rt.Compile() sTime := time.Date(2020, time.June, 28, 18, 56, 05, 0, time.UTC) eTime := sTime.Add(2 * time.Minute) eRTimes := [][]time.Time{ {time.Date(2020, time.June, 28, 18, 56, 0, 0, time.UTC), time.Time{}}, } if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRTimes, rTimes) { t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) } rt = &Rate{ ID: "RT_CHRISTMAS", Weights: DynamicWeights{ { Weight: 30, }, }, ActivationTimes: "* * 24 12 *", } rt.Compile() // sTime and eTime inside the activation interval sTime = time.Date(2020, 12, 24, 12, 0, 0, 0, time.UTC) eTime = sTime.Add(time.Hour) eRTimes = [][]time.Time{ {time.Date(2020, 12, 24, 12, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, } if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRTimes, rTimes) { t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) } // sTime smaller than activation time, eTime equals aTime sTime = time.Date(2020, 12, 23, 23, 0, 0, 0, time.UTC) eTime = sTime.Add(time.Hour) eRTimes = nil // cannot cover full interval if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRTimes, rTimes) { t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) } // sTime smaller than activation time but first aTime inside, eTime inside activation interval sTime = time.Date(2020, 12, 23, 23, 59, 59, 0, time.UTC) eTime = sTime.Add(time.Hour) eRTimes = [][]time.Time{ {time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, } if rTimes, err := rt.RunTimes(sTime, eTime, 1000000); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRTimes, rTimes) { t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) } // sTime way before aTime, eTime inside aInterval sTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) eTime = time.Date(2021, 12, 24, 0, 1, 0, 0, time.UTC) eRTimes = [][]time.Time{ {time.Date(2021, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2021, 12, 25, 0, 0, 0, 0, time.UTC)}, } if rTimes, err := rt.RunTimes(sTime, eTime, 1000000); err != nil { t.Error(err) } else if !reflect.DeepEqual(eRTimes, rTimes) { t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) } } func TestRateProfileRunTimesMaxIterations(t *testing.T) { rt := &Rate{ ID: "RATE0", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), }, }, ActivationTimes: "* * 24 12 *", } err := rt.Compile() if err != nil { t.Error(err) } sTime := time.Date(2020, 12, 24, 23, 30, 0, 0, time.UTC) eTime := time.Date(2021, 12, 25, 23, 30, 0, 0, time.UTC) expectedErr := "maximum iterations reached" if _, err := rt.RunTimes(sTime, eTime, 2); err == nil || err.Error() != expectedErr { t.Errorf("Expected %+v, received %+v", expectedErr, err) } } func TestRateProfileRunTimesPassingActivationTIme(t *testing.T) { rt := &Rate{ ID: "RATE0", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), }, }, ActivationTimes: "* * 24 * *", } err := rt.Compile() if err != nil { t.Error(err) } sTime := time.Date(2020, 12, 23, 0, 0, 0, 0, time.UTC) eTime := time.Date(2020, 12, 27, 0, 0, 0, 0, time.UTC) expectedTime := [][]time.Time{ {time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, } if rTimes, err := rt.RunTimes(sTime, eTime, 2); err != nil { t.Error(err) } else if !reflect.DeepEqual(expectedTime, rTimes) { t.Errorf("Expected %+v, received %+v", expectedTime, rTimes) } } func TestCostForIntervals(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rt0 := &Rate{ ID: "RATE0", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), Unit: minDecimal, Increment: minDecimal, RecurrentFee: NewDecimal(24, 1), }, { IntervalStart: NewDecimal(int64(60*time.Second), 0), Unit: minDecimal, Increment: secDecimal, RecurrentFee: NewDecimal(24, 1), }, }, } rt0.Compile() rt1 := &Rate{ ID: "RATE1", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), Unit: minDecimal, Increment: secDecimal, RecurrentFee: NewDecimal(12, 1), }, { IntervalStart: NewDecimal(int64(2*time.Minute), 0), Unit: minDecimal, Increment: secDecimal, RecurrentFee: NewDecimal(6, 1), }, }, } rt1.Compile() rtIvls := []*RateSInterval{ { IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rt0, IntervalRateIndex: 0, CompressFactor: 1, }, { IncrementStart: NewDecimal(int64(time.Minute), 0), Usage: NewDecimal(int64(30*time.Second), 0), Rate: rt0, IntervalRateIndex: 1, CompressFactor: 30, }, }, CompressFactor: 1, }, { IntervalStart: NewDecimal(int64(90*time.Second), 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(90*time.Second), 0), Usage: NewDecimal(int64(30*time.Second), 0), Rate: rt1, IntervalRateIndex: 0, CompressFactor: 30, }, { IncrementStart: NewDecimal(int64(2*time.Minute), 0), Usage: NewDecimal(int64(10*time.Minute), 0), Rate: rt1, IntervalRateIndex: 1, CompressFactor: 10, }, }, CompressFactor: 1, }, } eDcml, _ := new(decimal.Big).SetFloat64(4.3).Float64() if cost, _ := CostForIntervals(rtIvls).Float64(); cost != eDcml { t.Errorf("eDcml: %f, received: %+v", eDcml, cost) } } func TestCostForIntervalsWIthFixedFee(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rt0 := &Rate{ ID: "RATE0", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), FixedFee: NewDecimal(4, 1), RecurrentFee: NewDecimal(24, 1), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(60*time.Second), 0), RecurrentFee: NewDecimal(24, 1), Unit: minDecimal, Increment: secDecimal, }, }, } rt0.Compile() rt1 := &Rate{ ID: "RATE1", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), FixedFee: NewDecimal(2, 1), RecurrentFee: NewDecimal(12, 1), Unit: minDecimal, Increment: secDecimal, }, { IntervalStart: NewDecimal(int64(2*time.Minute), 0), RecurrentFee: NewDecimal(6, 1), Unit: minDecimal, Increment: secDecimal, }, }, } rt1.Compile() rtIvls := []*RateSInterval{ { IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { // cost 0,4 IncrementStart: NewDecimal(0, 0), Rate: rt0, IntervalRateIndex: 0, CompressFactor: 1, Usage: NewDecimal(-1, 0), }, { // cost 2,4 IncrementStart: NewDecimal(0, 0), Rate: rt0, IntervalRateIndex: 0, CompressFactor: 1, Usage: NewDecimal(int64(time.Minute), 0), }, { // cost 1,2 IncrementStart: NewDecimal(int64(time.Minute), 0), Rate: rt0, IntervalRateIndex: 1, CompressFactor: 30, Usage: NewDecimal(int64(30*time.Second), 0), }, }, CompressFactor: 1, }, { IntervalStart: NewDecimal(int64(90*time.Second), 0), Increments: []*RateSIncrement{ { // cost 0,2 IncrementStart: NewDecimal(int64(90*time.Second), 0), Rate: rt1, IntervalRateIndex: 0, CompressFactor: 1, Usage: NewDecimal(-1, 0), }, { // cost 0,6 IncrementStart: NewDecimal(int64(90*time.Second), 0), Rate: rt1, IntervalRateIndex: 0, CompressFactor: 30, Usage: NewDecimal(int64(30*time.Second), 0), }, { // cost 0,1 IncrementStart: NewDecimal(int64(2*time.Minute), 0), Rate: rt1, IntervalRateIndex: 1, CompressFactor: 10, Usage: NewDecimal(int64(10*time.Second), 0), }, }, CompressFactor: 1, }, } eDcml, _ := new(decimal.Big).SetFloat64(4.9).Float64() if cost, _ := CostForIntervals(rtIvls).Float64(); cost != eDcml { t.Errorf("eDcml: %f, received: %+v", eDcml, cost) } } func TestRateProfileCostCorrectCost(t *testing.T) { rPrfCost := &RateProfileCost{ ID: "Test1", Cost: 0.234, } rPrfCost.CorrectCost(IntPointer(2), MetaRoundingUp) if rPrfCost.Cost != 0.24 { t.Errorf("Expected: %+v, received: %+v", 0.24, rPrfCost.Cost) } if !reflect.DeepEqual(rPrfCost.Altered, []string{RoundingDecimals}) { t.Errorf("Expected: %+v, received: %+v", []string{RoundingDecimals}, rPrfCost.Altered) } } func TestRateProfileCostCorrectCostMinCost(t *testing.T) { testRPC := &RateProfileCost{ Cost: 0.5, MinCost: 1.5, } testRPC.CorrectCost(IntPointer(2), "") if testRPC.Cost != 1.5 { t.Errorf("\nExpecting: <1.5>,\n Received: <%+v>", testRPC.Cost) } } func TestRateProfileCostCorrectCostMaxCost(t *testing.T) { testRPC := &RateProfileCost{ Cost: 2.5, MaxCost: 1.5, } testRPC.CorrectCost(IntPointer(2), "") if testRPC.Cost != 1.5 { t.Errorf("\nExpecting: <1.5>,\n Received: <%+v>", testRPC.Cost) } } func TestRateSIncrementCompressEquals(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 3), Unit: minDecimal, Increment: secDecimal, }, }, uID: "testUID", } inCr1 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, } inCr2 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, } result := inCr1.CompressEquals(inCr2) if result != true { t.Errorf("\nExpecting: ,\n Received: <%+v>", result) } } func TestRateSIncrementCompressEqualsCase1(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, }, uID: "ID", } rate2 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, }, uID: "ID2", } inCr1 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, } inCr2 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate2, IntervalRateIndex: 0, CompressFactor: 1, } result := inCr1.CompressEquals(inCr2) if result != false { t.Errorf("\nExpecting: ,\n Received: <%+v>", result) } } func TestRateSIncrementCompressEqualsCase2(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, }, } inCr1 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, } inCr2 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 1, CompressFactor: 1, } result := inCr1.CompressEquals(inCr2) if result != false { t.Errorf("\nExpecting: ,\n Received: <%+v>", result) } } func TestRateSIncrementCompressEqualsCase3(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, }, } inCr1 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Second), 0), Rate: rate1, IntervalRateIndex: 1, CompressFactor: 1, } inCr2 := &RateSIncrement{ IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 1, CompressFactor: 1, } result := inCr1.CompressEquals(inCr2) if result != false { t.Errorf("\nExpecting: ,\n Received: <%+v>", result) } } func TestRateSIntervalCompressEqualsCase1(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 3), Unit: minDecimal, Increment: secDecimal, }, }, } rateSintrv1 := &RateSInterval{ IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, }, { IncrementStart: NewDecimal(int64(time.Minute), 0), Usage: NewDecimal(int64(time.Minute+10*time.Second), 0), Rate: rate1, IntervalRateIndex: 1, CompressFactor: 70, }, }, CompressFactor: 1, } rateSintrv2 := &RateSInterval{ IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, }, }, CompressFactor: 1, } result := rateSintrv1.CompressEquals(rateSintrv2) if result != false { t.Errorf("\nExpecting ,\nReceived <%+v>", result) } } func TestRateSIntervalCompressEqualsCase2(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 3), Unit: minDecimal, Increment: secDecimal, }, }, } rate2 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), RecurrentFee: NewDecimal(6, 3), Unit: minDecimal, Increment: secDecimal, }, }, } rateSintrv1 := &RateSInterval{ IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, }, { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Second), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, }, }, CompressFactor: 1, } rateSintrv2 := &RateSInterval{ IntervalStart: NewDecimal(1, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate2, IntervalRateIndex: 0, CompressFactor: 1, }, { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate2, IntervalRateIndex: 2, CompressFactor: 1, }, }, CompressFactor: 0, } result := rateSintrv1.CompressEquals(rateSintrv2) if result != false { t.Errorf("\nExpecting ,\nReceived <%+v>", result) } } func TestRateSIntervalCompressEqualsCase3(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } rate1 := &Rate{ ID: "RATE1", Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), Unit: minDecimal, Increment: minDecimal, }, }, } rateSintrv1 := &RateSInterval{ IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: rate1, IntervalRateIndex: 0, CompressFactor: 1, }, }, CompressFactor: 1, } rateSintrv2 := &RateSInterval{ IntervalStart: NewDecimal(0, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(0, 0), Rate: rate1, Usage: NewDecimal(int64(time.Minute), 0), IntervalRateIndex: 0, CompressFactor: 1, }, }, CompressFactor: 1, } result := rateSintrv1.CompressEquals(rateSintrv2) if result != true { t.Errorf("\nExpecting ,\nReceived <%+v>", result) } } func TestLibratesAsRateProfile(t *testing.T) { // Invalid DynamicWeights string ext := &APIRateProfile{ Weights: "testWeight", } rp := &RateProfile{ Tenant: ext.Tenant, ID: ext.ID, FilterIDs: ext.FilterIDs, ActivationInterval: ext.ActivationInterval, MaxCostStrategy: ext.MaxCostStrategy, } received, err := ext.AsRateProfile() experr := "invalid DynamicWeight format for string " if err == nil || err.Error() != experr { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", experr, err) } if received != nil { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", nil, received) } // No changes ext.Weights = EmptyString expected := rp received, err = ext.AsRateProfile() if err != nil { t.Errorf("\nExpected nil, got <%+v>", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } // assign MinCost to rp ext.MinCost = Float64Pointer(1) expected.MinCost = NewDecimal(1, 0) received, err = ext.AsRateProfile() if err != nil { t.Errorf("\nExpected nil, got <%+v>", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } // assign MaxCost to rp ext.MaxCost = Float64Pointer(2) expected.MaxCost = NewDecimal(2, 0) received, err = ext.AsRateProfile() if err != nil { t.Errorf("\nExpected nil, got <%+v>", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) } } func TestLibratesAsRateProfileNon0Len(t *testing.T) { id := "testID" ext := &APIRateProfile{ Rates: map[string]*APIRate{ "testKey": { ID: id, Weights: "testWeight", }, }, } rp := &RateProfile{ Tenant: ext.Tenant, ID: ext.ID, FilterIDs: ext.FilterIDs, ActivationInterval: ext.ActivationInterval, MaxCostStrategy: ext.MaxCostStrategy, } expected := rp expected.Rates = map[string]*Rate{ "testKey": nil, } received, err := ext.AsRateProfile() if err.Error() != "invalid DynamicWeight format for string " { t.Errorf("\nExpected nil, got <%+v>", err) } if !reflect.DeepEqual(received, expected) { t.Errorf("\nExpected: <%v>, \nReceived: <%v>", expected, received) } } func TestRatesIntervalEquals(t *testing.T) { rtInt1 := &RateSInterval{ IntervalStart: NewDecimal(int64(10*time.Second), 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(time.Second), 0), IntervalRateIndex: 1, Rate: &Rate{ uID: "newID", }, CompressFactor: 2, Usage: NewDecimal(int64(5*time.Second), 0), }, }, CompressFactor: 2, } rtInt2 := &RateSInterval{ IntervalStart: NewDecimal(int64(10*time.Second), 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(time.Second), 0), IntervalRateIndex: 1, Rate: &Rate{ uID: "newID", }, CompressFactor: 2, Usage: NewDecimal(int64(5*time.Second), 0), }, }, CompressFactor: 2, } // equals is looking for compressFactor if !rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are not equal", ToJSON(rtInt1), ToJSON(rtInt2)) } // not equals for IntervalStart rtInt1.IntervalStart = NewDecimal(int64(20*time.Second), 0) if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt1.IntervalStart = NewDecimal(int64(10*time.Second), 0) rtInt2.IntervalStart = NewDecimal(int64(20*time.Second), 0) if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt2.IntervalStart = NewDecimal(int64(10*time.Second), 0) // not equals for CompressFactor rtInt1.CompressFactor = 5 if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt1.CompressFactor = 2 rtInt2.CompressFactor = 8 if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt2.CompressFactor = 2 //not equals for Increments and their length rtInt1.Increments[0].Usage = NewDecimal(int64(90*time.Second), 0) if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt1.Increments[0].Usage = NewDecimal(int64(5*time.Second), 0) rtInt2.Increments[0].Usage = NewDecimal(int64(80*time.Second), 0) if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } rtInt2.Increments[0].Usage = NewDecimal(int64(5*time.Second), 0) rtInt1 = &RateSInterval{ IntervalStart: NewDecimal(int64(10*time.Second), 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(time.Second), 0), IntervalRateIndex: 1, Rate: &Rate{ uID: "newID", }, CompressFactor: 2, Usage: NewDecimal(int64(5*time.Second), 0), }, { IncrementStart: NewDecimal(int64(time.Second), 0), Usage: NewDecimal(int64(5*time.Second), 0), }, }, CompressFactor: 2, } if rtInt1.Equals(rtInt2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) } } func TestRatesIncrementEquals(t *testing.T) { incr1 := &RateSIncrement{ IncrementStart: NewDecimal(int64(time.Second), 0), IntervalRateIndex: 1, Rate: &Rate{ uID: "newID", }, CompressFactor: 2, Usage: NewDecimal(int64(5*time.Second), 0), } incr2 := &RateSIncrement{ IncrementStart: NewDecimal(int64(time.Second), 0), IntervalRateIndex: 1, Rate: &Rate{ uID: "newID", }, CompressFactor: 2, Usage: NewDecimal(int64(5*time.Second), 0), } // equals is not looking for compress factor if !incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are not equal", ToJSON(incr1), ToJSON(incr2)) } // not equals by IncrementStart incr1.IncrementStart = NewDecimal(int64(10*time.Second), 0) if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr1.IncrementStart = NewDecimal(int64(time.Second), 0) incr2.IncrementStart = NewDecimal(int64(10*time.Second), 0) if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr2.IncrementStart = NewDecimal(int64(time.Second), 0) // not equals by IntervalRateIndex incr1.IntervalRateIndex = 5 if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr1.IntervalRateIndex = 1 incr2.IntervalRateIndex = 5 if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr2.IntervalRateIndex = 1 //not equals by RateUID incr1.Rate.uID = "changed_uID" if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr1.Rate.uID = "newID" incr2.Rate.uID = "changed_uID" if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr2.Rate.uID = "newID" // not equals by CompressFactor incr1.CompressFactor = 0 if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr1.CompressFactor = 2 incr2.CompressFactor = 9 if incr1.Equals(incr2) { t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) } incr2.CompressFactor = 2 } func TestAsExtRateSInterval(t *testing.T) { minDecimal, err := NewDecimalFromUsage("1m") if err != nil { t.Error(err) } secDecimal, err := NewDecimalFromUsage("1s") if err != nil { t.Error(err) } rI := &RateSInterval{ IntervalStart: NewDecimal(int64(time.Second), 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(time.Nanosecond), 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: &Rate{ ID: "RATE1", FilterIDs: []string{"fltr1"}, Weights: DynamicWeights{ { Weight: 10, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), FixedFee: NewDecimal(4, 1), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(time.Minute), 0), Unit: minDecimal, Increment: secDecimal, }, }, }, IntervalRateIndex: 0, CompressFactor: 1, cost: NewDecimal(1000, 0).Big, }, { IncrementStart: NewDecimal(int64(time.Minute), 0), Usage: NewDecimal(int64(2*time.Minute), 0), Rate: &Rate{ ID: "RATE2", FilterIDs: []string{}, Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 5", IntervalRates: []*IntervalRate{ { RecurrentFee: NewDecimal(12, 2), FixedFee: NewDecimal(4, 1), Unit: minDecimal, Increment: minDecimal, }, { IntervalStart: NewDecimal(int64(30*time.Second), 0), Unit: minDecimal, Increment: secDecimal, }, }, }, IntervalRateIndex: 2, CompressFactor: 5, }, }, CompressFactor: 1, cost: NewDecimal(1234, 1).Big, } expRi := &ExtRateSInterval{ IntervalStart: Float64Pointer(float64(time.Second)), Increments: []*ExtRateSIncrement{ { IncrementStart: Float64Pointer(float64(time.Nanosecond)), Usage: Float64Pointer(float64(time.Minute)), Rate: &ExtRate{ ID: "RATE1", FilterIDs: []string{"fltr1"}, Weights: DynamicWeights{ { Weight: 10, }, }, ActivationTimes: "* * * * *", IntervalRates: []*ExtIntervalRate{ { IntervalStart: Float64Pointer(0), RecurrentFee: Float64Pointer(0.12), FixedFee: Float64Pointer(0.4), Unit: Float64Pointer(float64(time.Minute)), Increment: Float64Pointer(float64(time.Minute)), }, { IntervalStart: Float64Pointer(float64(time.Minute)), Unit: Float64Pointer(float64(time.Minute)), Increment: Float64Pointer(float64(time.Second)), }, }, }, IntervalRateIndex: 0, CompressFactor: 1, cost: Float64Pointer(1000), }, { IncrementStart: Float64Pointer(float64(time.Minute)), Usage: Float64Pointer(float64(2 * time.Minute)), Rate: &ExtRate{ ID: "RATE2", FilterIDs: []string{}, Weights: DynamicWeights{ { Weight: 0, }, }, ActivationTimes: "* * * * 5", IntervalRates: []*ExtIntervalRate{ { RecurrentFee: Float64Pointer(0.12), FixedFee: Float64Pointer(0.4), Unit: Float64Pointer(float64(time.Minute)), Increment: Float64Pointer(float64(time.Minute)), }, { IntervalStart: Float64Pointer(float64(30 * time.Second)), Unit: Float64Pointer(float64(time.Minute)), Increment: Float64Pointer(float64(time.Second)), }, }, }, IntervalRateIndex: 2, CompressFactor: 5, }, }, CompressFactor: 1, cost: Float64Pointer(123.4), } if rcv, err := rI.AsExtRateSInterval(); err != nil { t.Error(err) } else if !reflect.DeepEqual(rcv, expRi) { t.Errorf("Expected %+v \n, received %+v", ToJSON(expRi), ToJSON(rcv)) } } func TestAsExtRateSIntervalErrorsCheck(t *testing.T) { rI := &RateSInterval{ IntervalStart: NewDecimal(int64(math.Inf(1))-1, 0), Increments: []*RateSIncrement{ { IncrementStart: NewDecimal(int64(time.Nanosecond), 0), Usage: NewDecimal(int64(time.Minute), 0), Rate: &Rate{ ID: "RATE1", FilterIDs: []string{"fltr1"}, Weights: DynamicWeights{ { Weight: 10, }, }, ActivationTimes: "* * * * *", IntervalRates: []*IntervalRate{ { IntervalStart: NewDecimal(0, 0), RecurrentFee: NewDecimal(12, 2), FixedFee: NewDecimal(4, 1), //Unit: minDecimal, //Increment: minDecimal, }, }, }, IntervalRateIndex: 0, CompressFactor: 1, cost: NewDecimal(1000, 0).Big, }, }, CompressFactor: 1, cost: NewDecimal(1234, 1).Big, } expErr := "Cannot convert decimal IntervalStart into float64 " if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+v, received %+v", expErr, err) } rI.IntervalStart = NewDecimal(0, 0) rI.cost = NewDecimal(int64(math.Inf(1))-1, 0).Big expErr = "Cannot convert decimal cost into float64 " if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.cost = NewDecimal(0, 0).Big rI.Increments[0].IncrementStart = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "Cannot convert decimal IncrementStart into float64 " if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].IncrementStart = NewDecimal(0, 0) rI.Increments[0].Usage = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "Cannot convert decimal Usage into float64 " if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Usage = NewDecimal(0, 0) rI.Increments[0].cost = NewDecimal(int64(math.Inf(1))-1, 0).Big expErr = "Cannot convert decimal cost into float64 " if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].cost = NewDecimal(0, 0).Big rI.Increments[0].Rate.IntervalRates[0].IntervalStart = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "cannot convert decimal IntervalStart to float64" if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Rate.IntervalRates[0].IntervalStart = NewDecimal(0, 0) rI.Increments[0].Rate.IntervalRates[0].FixedFee = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "cannot convert decimal FixedFee to float64" if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Rate.IntervalRates[0].FixedFee = NewDecimal(0, 0) rI.Increments[0].Rate.IntervalRates[0].RecurrentFee = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "cannot convert decimal RecurrentFee to float64" if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Rate.IntervalRates[0].RecurrentFee = NewDecimal(0, 0) rI.Increments[0].Rate.IntervalRates[0].Unit = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "cannot convert decimal Unit to float64" if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Rate.IntervalRates[0].Unit = NewDecimal(0, 0) rI.Increments[0].Rate.IntervalRates[0].Increment = NewDecimal(int64(math.Inf(1))-1, 0) expErr = "cannot convert decimal Increment to float64" if _, err := rI.AsExtRateSInterval(); err == nil || err.Error() != expErr { t.Errorf("Expected %+q, received %+q", expErr, err) } rI.Increments[0].Rate.IntervalRates[0].Increment = NewDecimal(0, 0) }