From b4d743b73be240843e6678017174ffb9d0947b48 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 30 Sep 2014 00:21:51 +0300 Subject: [PATCH 1/4] saner hoepfully better GetNextTime also improved status response --- apier/v1/scheduler.go | 3 +- engine/action_timing.go | 83 ++++++++++++++-------------- engine/actions_test.go | 116 ++++++++++++++++++++++++++-------------- engine/responder.go | 15 +++--- engine/storage_sql.go | 4 +- 5 files changed, 124 insertions(+), 97 deletions(-) diff --git a/apier/v1/scheduler.go b/apier/v1/scheduler.go index 688702256..2c715793c 100644 --- a/apier/v1/scheduler.go +++ b/apier/v1/scheduler.go @@ -20,8 +20,9 @@ package v1 import ( "errors" - "github.com/cgrates/cgrates/utils" "time" + + "github.com/cgrates/cgrates/utils" ) /* diff --git a/engine/action_timing.go b/engine/action_timing.go index c636b6d99..d7064cb16 100644 --- a/engine/action_timing.go +++ b/engine/action_timing.go @@ -53,9 +53,19 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { if i == nil { return } + // Normalize + if i.Timing.StartTime == "" { + i.Timing.StartTime = "00:00:00" + } + if len(i.Timing.Years) > 0 && len(i.Timing.Months) == 0 { + i.Timing.Months = append(i.Timing.Months, 1) + } + if len(i.Timing.Months) > 0 && len(i.Timing.MonthDays) == 0 { + i.Timing.MonthDays = append(i.Timing.MonthDays, 1) + } y, m, d := now.Date() z, _ := now.Zone() - if i.Timing.StartTime != "" && i.Timing.StartTime != ASAP { + if i.Timing.StartTime != ASAP { l := fmt.Sprintf("%d-%d-%d %s %s", y, m, d, i.Timing.StartTime, z) var err error t, err = time.Parse(FORMAT, l) @@ -64,6 +74,9 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { at.stCache = t return } + if now.After(t) || now.Equal(t) { // Set it to next day this time + t = t.AddDate(0, 0, 1) + } } // weekdays if i.Timing.WeekDays != nil && len(i.Timing.WeekDays) > 0 { @@ -71,12 +84,12 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { if t.IsZero() { t = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()) } - d := t.Day() - for _, j := range []int{0, 1, 2, 3, 4, 5, 6, 7} { - t = time.Date(t.Year(), t.Month(), d, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location()).AddDate(0, 0, j) + for j := 0; j < 8; j++ { + n := t.AddDate(0, 0, j) for _, wd := range i.Timing.WeekDays { - if t.Weekday() == wd && (t.Equal(now) || t.After(now)) { - at.stCache = t + if n.Weekday() == wd && (n.Equal(now) || n.After(now)) { + at.stCache = n + t = n return } } @@ -85,15 +98,13 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { // monthdays if i.Timing.MonthDays != nil && len(i.Timing.MonthDays) > 0 { i.Timing.MonthDays.Sort() - year := now.Year() - month := now - x := sort.SearchInts(i.Timing.MonthDays, now.Day()) + year := t.Year() + month := t + x := sort.SearchInts(i.Timing.MonthDays, t.Day()) d = i.Timing.MonthDays[0] if x < len(i.Timing.MonthDays) { - if i.Timing.MonthDays[x] == now.Day() { + if i.Timing.MonthDays[x] == t.Day() { if t.Equal(now) || t.After(now) { - h, m, s := t.Clock() - t = time.Date(now.Year(), now.Month(), now.Day(), h, m, s, 0, time.Local) goto MONTHS } if x+1 < len(i.Timing.MonthDays) { // today was found in the list, jump to the next grater day @@ -107,11 +118,6 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { } else { // today was not found in the list, x is the first greater day d = i.Timing.MonthDays[x] } - } else { - if len(i.Timing.Months) == 0 { - t = time.Date(month.Year(), month.Month(), d, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - month = t - } } h, m, s := t.Clock() t = time.Date(month.Year(), month.Month(), d, h, m, s, 0, time.Local) @@ -119,22 +125,18 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { MONTHS: if i.Timing.Months != nil && len(i.Timing.Months) > 0 { i.Timing.Months.Sort() - year := now.Year() - x := sort.Search(len(i.Timing.Months), func(x int) bool { return i.Timing.Months[x] >= now.Month() }) + year := t.Year() + x := sort.Search(len(i.Timing.Months), func(x int) bool { return i.Timing.Months[x] >= t.Month() }) m = i.Timing.Months[0] if x < len(i.Timing.Months) { - if i.Timing.Months[x] == now.Month() { + if i.Timing.Months[x] == t.Month() { if t.Equal(now) || t.After(now) { - //h, m, s := t.Clock() - //t = time.Date(now.Year(), now.Month(), t.Day(), h, m, s, 0, time.Local) goto YEARS } if x+1 < len(i.Timing.Months) { // this month was found in the list so jump to next available month m = i.Timing.Months[x+1] // reset the monthday - if i.Timing.MonthDays != nil { - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } + t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } else { // jump to next year //not using now to make sure the next year has the the 1 date //(if today is 31) next month may not have it @@ -144,18 +146,15 @@ MONTHS: } else { // this month was not found in the list, x is the first greater month m = i.Timing.Months[x] // reset the monthday - if i.Timing.MonthDays != nil { - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - } - } else { - if len(i.Timing.Years) == 0 { - t = time.Date(year, m, t.Day(), 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - year = t.Year() + t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } } h, min, s := t.Clock() t = time.Date(year, m, t.Day(), h, min, s, 0, time.Local) + } else { + if now.After(t) { + t = t.AddDate(0, 1, 0) + } } YEARS: if i.Timing.Years != nil && len(i.Timing.Years) > 0 { @@ -177,24 +176,20 @@ YEARS: t = time.Date(t.Year(), i.Timing.Months[0], t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } // reset the monthday - if i.Timing.MonthDays != nil { - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } + t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } } else { // this year was not found in the list, x is the first greater year y = i.Timing.Years[x] - // reset the month - if i.Timing.Months != nil { - t = time.Date(t.Year(), i.Timing.Months[0], t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - // reset the monthday - if i.Timing.MonthDays != nil { - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } + // reset the month/monthday + t = time.Date(t.Year(), i.Timing.Months[0], i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } } h, min, s := t.Clock() t = time.Date(y, t.Month(), t.Day(), h, min, s, 0, time.Local) + } else { + if now.After(t) { + t = t.AddDate(1, 0, 0) + } } at.stCache = t return diff --git a/engine/actions_test.go b/engine/actions_test.go index 3758a52c4..2dcd6f530 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -28,13 +28,23 @@ import ( ) var ( - //referenceDate = time.Date(2014, 1, 1, 0, 0, 0, 0, time.Local) //referenceDate = time.Date(2013, 7, 10, 10, 30, 0, 0, time.Local) //referenceDate = time.Date(2013, 12, 31, 23, 59, 59, 0, time.Local) + //referenceDate = time.Date(2011, 1, 1, 0, 0, 0, 1, time.Local) referenceDate = time.Now() now = referenceDate ) +func TestActionTimingAlways(t *testing.T) { + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}} + st := at.GetNextStartTime(referenceDate) + y, m, d := referenceDate.Date() + expected := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + func TestActionTimingNothing(t *testing.T) { at := &ActionTiming{} st := at.GetNextStartTime(referenceDate) @@ -50,6 +60,9 @@ func TestActionTimingOnlyHour(t *testing.T) { y, m, d := now.Date() expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + if referenceDate.After(expected) { + expected = expected.AddDate(0, 0, 1) + } if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -58,9 +71,7 @@ func TestActionTimingOnlyHour(t *testing.T) { func TestActionTimingHourYear(t *testing.T) { at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2012}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) - - _, m, d := now.Date() - expected := time.Date(2012, m, d, 10, 1, 0, 0, time.Local) + expected := time.Date(2012, 1, 1, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -74,9 +85,11 @@ func TestActionTimingOnlyWeekdays(t *testing.T) { h, min, s := now.Clock() e := time.Date(y, m, d, h, min, s, 0, time.Local) day := e.Day() - for _, i := range []int{0, 1, 2, 3, 4, 5, 6, 7} { - e = time.Date(e.Year(), e.Month(), day, e.Hour(), e.Minute(), e.Second(), e.Nanosecond(), e.Location()).AddDate(0, 0, i) - if e.Weekday() == time.Monday && (e.Equal(now) || e.After(now)) { + e = time.Date(e.Year(), e.Month(), day, 0, 0, 0, 0, e.Location()) + for i := 0; i < 8; i++ { + n := e.AddDate(0, 0, i) + if n.Weekday() == time.Monday && (n.Equal(now) || n.After(now)) { + e = n break } } @@ -92,9 +105,11 @@ func TestActionTimingHourWeekdays(t *testing.T) { y, m, d := now.Date() e := time.Date(y, m, d, 10, 1, 0, 0, time.Local) day := e.Day() - for _, i := range []int{0, 1, 2, 3, 4, 5, 6, 7} { - e = time.Date(e.Year(), e.Month(), day, e.Hour(), e.Minute(), e.Second(), e.Nanosecond(), e.Location()).AddDate(0, 0, i) - if e.Weekday() == time.Monday && (e.Equal(now) || e.After(now)) { + for i := 0; i < 8; i++ { + e = time.Date(e.Year(), e.Month(), day, e.Hour(), e.Minute(), e.Second(), e.Nanosecond(), e.Location()) + n := e.AddDate(0, 0, i) + if n.Weekday() == time.Monday && (n.Equal(now) || n.After(now)) { + e = n break } } @@ -148,6 +163,10 @@ func TestActionTimingHourMonths(t *testing.T) { y, m, d := now.Date() testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + if now.After(testTime) { + testTime = testTime.AddDate(0, 0, 1) + y, m, d = testTime.Date() + } nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) if now.After(testTime) { m = nextMonth.Month() @@ -158,7 +177,10 @@ func TestActionTimingHourMonths(t *testing.T) { Months: utils.Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + expected := time.Date(y, m, 1, 10, 1, 0, 0, time.Local) + if referenceDate.After(expected) { + expected = expected.AddDate(0, 1, 0) + } if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -212,12 +234,11 @@ func TestActionTimingFirstOfTheMonth(t *testing.T) { } func TestActionTimingOnlyYears(t *testing.T) { - - y, m, d := now.Date() - nextYear := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) + y, _, _ := referenceDate.Date() + nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(nextYear.Year(), 1, 1, 0, 0, 0, 0, time.Local) + expected := nextYear if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -233,17 +254,12 @@ func TestActionTimingPast(t *testing.T) { } func TestActionTimingHourYears(t *testing.T) { - - y, m, d := now.Date() - testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) - nextYear := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - year := now.Year() - if now.After(testTime) { - year = nextYear.Year() - } - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(year, m, d, 10, 1, 0, 0, time.Local) + expected := time.Date(referenceDate.Year(), 1, 1, 10, 1, 0, 0, time.Local) + if referenceDate.After(expected) { + expected = expected.AddDate(1, 0, 0) + } if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -252,17 +268,16 @@ func TestActionTimingHourYears(t *testing.T) { func TestActionTimingHourMonthdaysYear(t *testing.T) { y, m, d := now.Date() - testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) - nextYear := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) + testTime := time.Date(y, 1, d, 10, 1, 0, 0, time.Local) tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - if now.After(testTime) { - y, m, d = tomorrow.Date() - } - nextDay := time.Date(y, m, d, 10, 1, 0, 0, time.Local) - year := nextDay.Year() - if nextDay.Before(now) { - if now.After(testTime) { - year = nextYear.Year() + nextYear := time.Date(y, 1, 1, 10, 1, 0, 0, time.Local).AddDate(1, 0, 0) + nextDay := time.Date(y, 1, 1, 10, 1, 0, 0, time.Local).AddDate(1, 0, 0) + expected := testTime + if referenceDate.After(testTime) { + if referenceDate.After(nextDay) { + expected = nextYear + } else { + expected = nextDay } } at := &ActionTiming{Timing: &RateInterval{ @@ -273,7 +288,6 @@ func TestActionTimingHourMonthdaysYear(t *testing.T) { }, }} st := at.GetNextStartTime(referenceDate) - expected := time.Date(year, m, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -339,14 +353,34 @@ func TestActionTimingFirstOfTheYear(t *testing.T) { func TestActionTimingFirstMonthOfTheYear(t *testing.T) { y, _, _ := now.Date() - nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) + expected := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local) + if referenceDate.After(expected) { + expected = expected.AddDate(1, 0, 0) + } at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{time.January}, }, }} st := at.GetNextStartTime(referenceDate) - expected := nextYear + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + +func TestActionTimingFirstMonthOfTheYearSecondDay(t *testing.T) { + y, _, _ := now.Date() + expected := time.Date(y, 1, 2, 0, 0, 0, 0, time.Local) + if referenceDate.After(expected) { + expected = expected.AddDate(1, 0, 0) + } + at := &ActionTiming{Timing: &RateInterval{ + Timing: &RITiming{ + Months: utils.Months{time.January}, + MonthDays: utils.MonthDays{2}, + }, + }} + st := at.GetNextStartTime(referenceDate) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -909,8 +943,8 @@ func TestActionTriggerLogging(t *testing.T) { _ = k _ = v /*if strings.Contains(k, LOG_ACTION_TRIGGER_PREFIX) && strings.Contains(v, expected) { - key = k - break + key = k + break }*/ } if key != "" { @@ -953,7 +987,7 @@ func TestActionTimingLogging(t *testing.T) { _ = k _ = v /*if strings.Contains(k, LOG_ACTION_TIMMING_PREFIX) && strings.Contains(string(v), expected) { - key = k + key = k }*/ } if key != "" { diff --git a/engine/responder.go b/engine/responder.go index 906a343a7..00baccfcf 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -152,19 +152,16 @@ func (rs *Responder) FlushCache(arg CallDescriptor, reply *float64) (err error) return } -func (rs *Responder) Status(arg string, reply *string) (err error) { +func (rs *Responder) Status(arg string, reply *map[string]interface{}) (err error) { memstats := new(runtime.MemStats) runtime.ReadMemStats(memstats) + response := make(map[string]interface{}) if rs.Bal != nil { - - *reply = "Connected raters:\n" - for _, rater := range rs.Bal.GetClientAddresses() { - *reply += fmt.Sprintf("%v\n", rater) - } - *reply += fmt.Sprintf("memstats before GC: %dKb footprint: %dKb", memstats.HeapAlloc/1024, memstats.Sys/1024) - } else { - *reply = fmt.Sprintf("memstats before GC: %dKb footprint: %dKb", memstats.HeapAlloc/1024, memstats.Sys/1024) + response["Raters"] = rs.Bal.GetClientAddresses() } + response["memstat"] = memstats.HeapAlloc / 1024 + response["footprint"] = memstats.Sys / 1024 + *reply = response return } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 8a20310c5..231888feb 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -523,8 +523,8 @@ func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string][]*utils. }) } } - tx.Commit() - return nil + r := tx.Commit() + return r.Error } func (self *SQLStorage) GetTPActionTimings(tpid, tag string) (map[string][]*utils.TPActionTiming, error) { From 5e5aa78579b937e6740e901b8cc64a353ea5107b Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 30 Sep 2014 12:02:03 +0300 Subject: [PATCH 2/4] fix failing test --- engine/actions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/actions_test.go b/engine/actions_test.go index 2dcd6f530..7c9847705 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -163,11 +163,11 @@ func TestActionTimingHourMonths(t *testing.T) { y, m, d := now.Date() testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) if now.After(testTime) { testTime = testTime.AddDate(0, 0, 1) y, m, d = testTime.Date() } - nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) if now.After(testTime) { m = nextMonth.Month() y = nextMonth.Year() From b669f2e8ac20dafcfd01b1c4245d067d695254cc Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 30 Sep 2014 19:05:41 +0300 Subject: [PATCH 3/4] using extrenal lib for next date --- engine/action_timing.go | 24 +++++++++++++ engine/actions_test.go | 12 +++---- engine/loader_csv_test.go | 26 +++++++------- engine/rateinterval.go | 68 ++++++++++++++++++++++++++++++++++++ engine/rateinterval_test.go | 56 ++++++++++++++++++++++++++++- hard_update_external_libs.py | 1 + update_external_libs.sh | 1 + 7 files changed, 168 insertions(+), 20 deletions(-) diff --git a/engine/action_timing.go b/engine/action_timing.go index d7064cb16..6d19f9a1b 100644 --- a/engine/action_timing.go +++ b/engine/action_timing.go @@ -25,6 +25,7 @@ import ( "time" "github.com/cgrates/cgrates/utils" + "github.com/gorhill/cronexpr" ) const ( @@ -46,6 +47,29 @@ type ActionTiming struct { type ActionPlan []*ActionTiming func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { + if !at.stCache.IsZero() { + return at.stCache + } + i := at.Timing + if i == nil || i.Timing == nil { + return + } + // Normalize + if i.Timing.StartTime == "" { + i.Timing.StartTime = "00:00:00" + } + if len(i.Timing.Years) > 0 && len(i.Timing.Months) == 0 { + i.Timing.Months = append(i.Timing.Months, 1) + } + if len(i.Timing.Months) > 0 && len(i.Timing.MonthDays) == 0 { + i.Timing.MonthDays = append(i.Timing.MonthDays, 1) + } + at.stCache = cronexpr.MustParse(i.Timing.CronString()).Next(now) + return at.stCache +} + +// To be deleted after the above solution proves reliable +func (at *ActionTiming) GetNextStartTimeOld(now time.Time) (t time.Time) { if !at.stCache.IsZero() { return at.stCache } diff --git a/engine/actions_test.go b/engine/actions_test.go index 7c9847705..65fc71a24 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -69,9 +69,9 @@ func TestActionTimingOnlyHour(t *testing.T) { } func TestActionTimingHourYear(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2012}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2022}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(2012, 1, 1, 10, 1, 0, 0, time.Local) + expected := time.Date(2022, 1, 1, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -245,9 +245,9 @@ func TestActionTimingOnlyYears(t *testing.T) { } func TestActionTimingPast(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2013}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2023}}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(2013, 1, 1, 0, 0, 0, 0, time.Local) + expected := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -411,7 +411,7 @@ func TestActionTimingLogFunction(t *testing.T) { func TestActionTimingPriotityListSortByWeight(t *testing.T) { at1 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2100}, + Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", @@ -420,7 +420,7 @@ func TestActionTimingPriotityListSortByWeight(t *testing.T) { }} at2 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2100}, + Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: utils.MonthDays{2}, StartTime: "00:00:00", diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index c31e82a91..45cc649ad 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -532,28 +532,28 @@ func TestLoadRatingPlans(t *testing.T) { expected := &RatingPlan{ Id: "STANDARD", Timings: map[string]*RITiming{ - "14ae6e41": &RITiming{ + "4c954a4f": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", }, - "9a6f8e32": &RITiming{ + "4d593287": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", }, - "7181e535": &RITiming{ + "a60bfb13": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", }, - "96c78ff5": &RITiming{ + "30eab300": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -618,48 +618,48 @@ func TestLoadRatingPlans(t *testing.T) { DestinationRates: map[string]RPRateList{ "GERMANY": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "822a5aef", Weight: 10, }, &RPRate{ - Timing: "9a6f8e32", + Timing: "4d593287", Rating: "4a25c533", Weight: 10, }, &RPRate{ - Timing: "7181e535", + Timing: "a60bfb13", Rating: "4a25c533", Weight: 10, }, }, "GERMANY_O2": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "4a25c533", Weight: 10, }, &RPRate{ - Timing: "9a6f8e32", + Timing: "4d593287", Rating: "b05c5f6b", Weight: 10, }, &RPRate{ - Timing: "7181e535", + Timing: "a60bfb13", Rating: "b05c5f6b", Weight: 10, }, }, "GERMANY_PREMIUM": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "4a25c533", Weight: 10, }, }, "URG": []*RPRate{ &RPRate{ - Timing: "96c78ff5", + Timing: "30eab300", Rating: "9f49ef8e", Weight: 20, }, @@ -667,7 +667,7 @@ func TestLoadRatingPlans(t *testing.T) { }, } if !reflect.DeepEqual(rplan, expected) { - t.Errorf("Error loading destination rate timing: %+v", rplan.DestinationRates["URG"][0]) + t.Errorf("Error loading destination rate timing: %+v", rplan.DestinationRates["GERMANY_O2"][0]) } } diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 535fb73f6..7b0f8b176 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -45,6 +45,74 @@ type RITiming struct { MonthDays utils.MonthDays WeekDays utils.WeekDays StartTime, EndTime string // ##:##:## format + cronString string +} + +func (rit *RITiming) CronString() string { + if rit.cronString != "" { + return rit.cronString + } + var sec, min, hour, monthday, month, weekday, year string + if len(rit.StartTime) == 0 { + hour, min, sec = "*", "*", "*" + } else { + hms := strings.Split(rit.StartTime, ":") + if len(hms) != 3 { + hour, min, sec = "*", "*", "*" + } + hour, min, sec = hms[0], hms[1], hms[2] + if strings.HasPrefix(hour, "0") { + hour = hour[1:] + } + if strings.HasPrefix(min, "0") { + min = min[1:] + } + if strings.HasPrefix(sec, "0") { + sec = sec[1:] + } + } + if len(rit.MonthDays) == 0 { + monthday = "*" + } else { + for i, md := range rit.MonthDays { + if i > 0 { + monthday += "," + } + monthday += strconv.Itoa(md) + } + } + if len(rit.Months) == 0 { + month = "*" + } else { + for i, md := range rit.Months { + if i > 0 { + month += "," + } + month += strconv.Itoa(int(md)) + } + } + if len(rit.WeekDays) == 0 { + weekday = "*" + } else { + for i, md := range rit.WeekDays { + if i > 0 { + weekday += "," + } + weekday += strconv.Itoa(int(md)) + } + } + if len(rit.Years) == 0 { + year = "*" + } else { + for i, md := range rit.Years { + if i > 0 { + year += "," + } + year += strconv.Itoa(int(md)) + } + } + rit.cronString = fmt.Sprintf("%s %s %s %s %s %s %s", sec, min, hour, monthday, month, weekday, year) + return rit.cronString } func (rit *RITiming) Stringify() string { diff --git a/engine/rateinterval_test.go b/engine/rateinterval_test.go index de24999a3..980fb2f20 100644 --- a/engine/rateinterval_test.go +++ b/engine/rateinterval_test.go @@ -19,9 +19,10 @@ along with this program. If not, see package engine import ( - "github.com/cgrates/cgrates/utils" "testing" "time" + + "github.com/cgrates/cgrates/utils" ) func TestRateIntervalSimpleContains(t *testing.T) { @@ -283,6 +284,59 @@ func TestRateStrigyfy(t *testing.T) { } } +func TestRateIntervalCronAll(t *testing.T) { + rit := &RITiming{ + Years: utils.Years{2012}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, + WeekDays: []time.Weekday{time.Sunday}, + StartTime: "14:30:00", + } + expected := "0 30 14 1 2 0 2012" + cron := rit.CronString() + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronMultiple(t *testing.T) { + rit := &RITiming{ + Years: utils.Years{2012, 2014}, + Months: utils.Months{time.February, time.January}, + MonthDays: utils.MonthDays{15, 16}, + WeekDays: []time.Weekday{time.Sunday, time.Monday}, + StartTime: "14:30:00", + } + expected := "0 30 14 15,16 2,1 0,1 2012,2014" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronStar(t *testing.T) { + rit := &RITiming{ + StartTime: "*:30:00", + } + expected := "0 30 * * * * *" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronEmpty(t *testing.T) { + rit := &RITiming{} + expected := "* * * * * * *" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + /*********************************Benchmarks**************************************/ func BenchmarkRateIntervalContainsDate(b *testing.B) { diff --git a/hard_update_external_libs.py b/hard_update_external_libs.py index bb59c3f72..c281908fd 100755 --- a/hard_update_external_libs.py +++ b/hard_update_external_libs.py @@ -14,6 +14,7 @@ libs = ('code.google.com/p/goconf/conf', 'github.com/hoisie/redis' 'github.com/howeyc/fsnotify', 'github.com/jinzhu/gorm', + 'github.com/gorhill/cronexpr', ) if __name__ == "__main__": diff --git a/update_external_libs.sh b/update_external_libs.sh index 95453330c..74ef16f04 100755 --- a/update_external_libs.sh +++ b/update_external_libs.sh @@ -11,3 +11,4 @@ go get -u -v github.com/howeyc/fsnotify go get -u -v github.com/cgrates/liner go get -u -v github.com/cgrates/rpcclient go get -u -v github.com/jinzhu/gorm +go get -u -v github.com/gorhill/cronexpr From 88791968ef3b3213a3741fcaa6e5e0b9bae7453a Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 1 Oct 2014 18:28:38 +0300 Subject: [PATCH 4/4] pagination for cdrs and more api for cache and accounts --- apier/v1/accounts.go | 15 +++++++ apier/v1/cdre.go | 2 +- apier/v1/cdrs.go | 5 ++- apier/v1/scheduler.go | 12 ++++- engine/mediator.go | 2 +- engine/mediator_local_test.go | 14 +++--- engine/storage_interface.go | 3 +- engine/storage_map.go | 4 ++ engine/storage_mongo.go | 4 ++ engine/storage_redis.go | 4 ++ engine/storage_sql.go | 12 ++++- engine/storage_sql_local_test.go | 75 ++++++++++++++++---------------- utils/apitpdata.go | 5 ++- 13 files changed, 104 insertions(+), 53 deletions(-) diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index a574e61af..41aff4a8c 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -219,3 +219,18 @@ func (self *ApierV1) SetAccount(attr AttrSetAccount, reply *string) error { *reply = OK // This will mark saving of the account, error still can show up in actionTimingsId return nil } + +type AttrGetAccounts struct { + Page int + ItemsPerPage int + SearchTerm string +} + +func (self *ApierV1) GetAccounts(attr AttrGetAccounts, reply *[]string) error { + accountKeys, err := self.AccountDb.GetKeysForPrefix(engine.ACCOUNT_PREFIX) + if err != nil { + return err + } + *reply = accountKeys + return nil +} diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go index de92ebfe5..78e62c2b6 100644 --- a/apier/v1/cdre.go +++ b/apier/v1/cdre.go @@ -185,7 +185,7 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E } cdrs, err := self.CdrDb.GetStoredCdrs(attr.CgrIds, attr.MediationRunIds, attr.TORs, attr.CdrHosts, attr.CdrSources, attr.ReqTypes, attr.Directions, attr.Tenants, attr.Categories, attr.Accounts, attr.Subjects, attr.DestinationPrefixes, attr.RatedAccounts, attr.RatedSubjects, attr.OrderIdStart, attr.OrderIdEnd, - tStart, tEnd, attr.SkipErrors, attr.SkipRated, false) + tStart, tEnd, attr.SkipErrors, attr.SkipRated, false, nil) if err != nil { return err } else if len(cdrs) == 0 { diff --git a/apier/v1/cdrs.go b/apier/v1/cdrs.go index 3873199da..88459d1a7 100644 --- a/apier/v1/cdrs.go +++ b/apier/v1/cdrs.go @@ -20,9 +20,10 @@ package v1 import ( "fmt" + "time" + "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" - "time" ) type AttrGetCallCost struct { @@ -61,7 +62,7 @@ func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*utils.CgrCdrOut } if cdrs, err := apier.CdrDb.GetStoredCdrs(attrs.CgrIds, attrs.MediationRunIds, attrs.TORs, attrs.CdrHosts, attrs.CdrSources, attrs.ReqTypes, attrs.Directions, attrs.Tenants, attrs.Categories, attrs.Accounts, attrs.Subjects, attrs.DestinationPrefixes, attrs.RatedAccounts, attrs.RatedSubjects, - attrs.OrderIdStart, attrs.OrderIdEnd, tStart, tEnd, attrs.SkipErrors, attrs.SkipRated, false); err != nil { + attrs.OrderIdStart, attrs.OrderIdEnd, tStart, tEnd, attrs.SkipErrors, attrs.SkipRated, false, &utils.TPPagination{Page: attrs.Page, ItemsPerPage: attrs.ItemsPerPage, SearchTerm: attrs.SearchTerm}); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else { for _, cdr := range cdrs { diff --git a/apier/v1/scheduler.go b/apier/v1/scheduler.go index 2c715793c..6b8af2e42 100644 --- a/apier/v1/scheduler.go +++ b/apier/v1/scheduler.go @@ -99,6 +99,9 @@ import ( type AttrsGetScheduledActions struct { Direction, Tenant, Account string TimeStart, TimeEnd time.Time // Filter based on next runTime + Page int + ItemsPerPage int + SearchTerm string } type ScheduledActions struct { @@ -112,7 +115,14 @@ func (self *ApierV1) GetScheduledActions(attrs AttrsGetScheduledActions, reply * if self.Sched == nil { return errors.New("SCHEDULER_NOT_ENABLED") } - for _, qActions := range self.Sched.GetQueue() { + scheduledActions := self.Sched.GetQueue() + paginator := &utils.TPPagination{Page: attrs.Page, ItemsPerPage: attrs.ItemsPerPage, SearchTerm: attrs.SearchTerm} + min, max := paginator.GetLimits() + if max > len(scheduledActions) { + max = len(scheduledActions) + } + scheduledActions = scheduledActions[min : min+max] + for _, qActions := range scheduledActions { sas := &ScheduledActions{ActionsId: qActions.ActionsId, ActionPlanId: qActions.Id, ActionPlanUuid: qActions.Uuid} sas.NextRunTime = qActions.GetNextStartTime(time.Now()) if !attrs.TimeStart.IsZero() && sas.NextRunTime.Before(attrs.TimeStart) { diff --git a/engine/mediator.go b/engine/mediator.go index d67e6d153..1cc1eb807 100644 --- a/engine/mediator.go +++ b/engine/mediator.go @@ -187,7 +187,7 @@ func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) erro func (self *Mediator) RateCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes, ratedAccounts, ratedSubjects []string, orderIdStart, orderIdEnd int64, timeStart, timeEnd time.Time, rerateErrors, rerateRated, sendToStats bool) error { cdrs, err := self.cdrDb.GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes, ratedAccounts, ratedSubjects, - orderIdStart, orderIdEnd, timeStart, timeEnd, !rerateErrors, !rerateRated, true) + orderIdStart, orderIdEnd, timeStart, timeEnd, !rerateErrors, !rerateRated, true, nil) if err != nil { return err } diff --git a/engine/mediator_local_test.go b/engine/mediator_local_test.go index 96188cd42..a35481487 100644 --- a/engine/mediator_local_test.go +++ b/engine/mediator_local_test.go @@ -156,12 +156,12 @@ func TestPostCdrs(t *testing.T) { } } time.Sleep(100 * time.Millisecond) // Give time for CDRs to reach database - if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false); err != nil { + if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false, nil); err != nil { t.Error(err) } else if len(storedCdrs) != 6 { // Make sure CDRs made it into StorDb t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs))) } - if nonErrorCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, false, false); err != nil { + if nonErrorCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, false, false, nil); err != nil { t.Error(err) } else if len(nonErrorCdrs) != 0 { t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(nonErrorCdrs))) @@ -184,12 +184,12 @@ func TestInjectCdrs(t *testing.T) { t.Error(err) } } - if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false); err != nil { + if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false, nil); err != nil { t.Error(err) } else if len(storedCdrs) != 8 { // Make sure CDRs made it into StorDb t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs))) } - if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false); err != nil { + if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false, nil); err != nil { t.Error(err) } else if len(nonRatedCdrs) != 2 { // Just two of them should be non-rated t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs))) @@ -221,12 +221,12 @@ func TestRateCdrs(t *testing.T) { } else if reply != utils.OK { t.Errorf("Unexpected reply: %s", reply) } - if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false); err != nil { + if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false, nil); err != nil { t.Error(err) } else if len(nonRatedCdrs) != 0 { // All CDRs should be rated t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs))) } - if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false); err != nil { + if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false, nil); err != nil { t.Error(err) } else if len(errRatedCdrs) != 8 { // The first 2 with errors should be still there before rerating t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs))) @@ -236,7 +236,7 @@ func TestRateCdrs(t *testing.T) { } else if reply != utils.OK { t.Errorf("Unexpected reply: %s", reply) } - if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false); err != nil { + if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false, nil); err != nil { t.Error(err) } else if len(errRatedCdrs) != 4 { t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs))) diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 21e892b6a..973f6726c 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -65,6 +65,7 @@ const ( type Storage interface { Close() Flush() error + GetKeysForPrefix(string) ([]string, error) } /* @@ -117,7 +118,7 @@ type CdrStorage interface { SetCdr(*utils.StoredCdr) error SetRatedCdr(*utils.StoredCdr, string) error GetStoredCdrs([]string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, - int64, int64, time.Time, time.Time, bool, bool, bool) ([]*utils.StoredCdr, error) + int64, int64, time.Time, time.Time, bool, bool, bool, *utils.TPPagination) ([]*utils.StoredCdr, error) RemStoredCdrs([]string) error } diff --git a/engine/storage_map.go b/engine/storage_map.go index c9296d62e..944bc4007 100644 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -52,6 +52,10 @@ func (ms *MapStorage) Flush() error { return nil } +func (ms *MapStorage) GetKeysForPrefix(string) ([]string, error) { + return nil, nil +} + func (ms *MapStorage) CacheRating(dKeys, rpKeys, rpfKeys, alsKeys, lcrKeys []string) error { cache2go.BeginTransaction() if dKeys == nil { diff --git a/engine/storage_mongo.go b/engine/storage_mongo.go index c546fc734..c76ea8c8c 100644 --- a/engine/storage_mongo.go +++ b/engine/storage_mongo.go @@ -63,6 +63,10 @@ func (ms *MongoStorage) Close() { ms.session.Close() } +func (ms *MongoStorage) GetKeysForPrefix(prefix string) ([]string, error) { + return nil, nil +} + func (ms *MongoStorage) Flush() (err error) { err = ms.db.C("ratingprofiles").DropCollection() if err != nil { diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 566db1ec1..6b0aaeb37 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -67,6 +67,10 @@ func (rs *RedisStorage) Flush() (err error) { return } +func (rs *RedisStorage) GetKeysForPrefix(prefix string) ([]string, error) { + return rs.db.Keys(prefix + "*") +} + func (rs *RedisStorage) CacheRating(dKeys, rpKeys, rpfKeys, alsKeys, lcrKeys []string) (err error) { cache2go.BeginTransaction() if dKeys == nil { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 231888feb..07ed44975 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -60,6 +60,10 @@ func (self *SQLStorage) Flush() (err error) { return nil } +func (self *SQLStorage) GetKeysForPrefix(prefix string) ([]string, error) { + return nil, nil +} + func (self *SQLStorage) CreateTablesFromScript(scriptPath string) error { fileContent, err := ioutil.ReadFile(scriptPath) if err != nil { @@ -125,7 +129,7 @@ func (self *SQLStorage) GetTPTableIds(tpid, table string, distinct utils.TPDisti qry += fmt.Sprintf(")") } if pagination != nil { - limLow, limHigh := pagination.GetLimit() + limLow, limHigh := pagination.GetLimits() qry += fmt.Sprintf(" LIMIT %d,%d", limLow, limHigh) } @@ -734,7 +738,7 @@ func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string // ignoreErr - do not consider cdrs with rating errors // ignoreRated - do not consider cdrs which were already rated, including here the ones with errors func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes, ratedAccounts, ratedSubjects []string, - orderIdStart, orderIdEnd int64, timeStart, timeEnd time.Time, ignoreErr, ignoreRated, ignoreDerived bool) ([]*utils.StoredCdr, error) { + orderIdStart, orderIdEnd int64, timeStart, timeEnd time.Time, ignoreErr, ignoreRated, ignoreDerived bool, pagination *utils.TPPagination) ([]*utils.StoredCdr, error) { var cdrs []*utils.StoredCdr var q *bytes.Buffer // Need to query differently since in case of primary, unmediated CDRs some values will be missing if ignoreDerived { @@ -1053,6 +1057,10 @@ func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources if fltr.Len() != 0 { q.WriteString(fmt.Sprintf(" WHERE %s", fltr.String())) } + if pagination != nil { + limLow, limHigh := pagination.GetLimits() + q.WriteString(fmt.Sprintf(" LIMIT %d,%d", limLow, limHigh)) + } rows, err := self.Db.Query(q.String()) if err != nil { return nil, err diff --git a/engine/storage_sql_local_test.go b/engine/storage_sql_local_test.go index 8f6577f25..caad42bcc 100644 --- a/engine/storage_sql_local_test.go +++ b/engine/storage_sql_local_test.go @@ -20,12 +20,13 @@ package engine import ( "fmt" - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" "path" "reflect" "testing" "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" ) /* @@ -257,7 +258,7 @@ func TestGetStoredCdrs(t *testing.T) { } var timeStart, timeEnd time.Time // All CDRs, no filter - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -265,7 +266,7 @@ func TestGetStoredCdrs(t *testing.T) { // Filter on cgrids if storedCdrs, err := mysqlDb.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -273,172 +274,172 @@ func TestGetStoredCdrs(t *testing.T) { // Filter on cgrids plus reqType if storedCdrs, err := mysqlDb.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, - nil, nil, nil, nil, []string{"prepaid"}, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, []string{"prepaid"}, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on runId if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, []string{utils.DEFAULT_RUNID}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on TOR if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, []string{utils.SMS}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 0 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple TOR if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, []string{utils.SMS, utils.VOICE}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cdrHost if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.2"}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple cdrHost if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.1", "192.168.1.2"}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false, false); err != nil { + 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cdrSource if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN"}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple cdrSource if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN", "UNKNOWN2"}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on reqType if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid"}, - nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple reqType if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid", "pseudoprepaid"}, nil, nil, nil, nil, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false, false); err != nil { + 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on direction - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, []string{"*out"}, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, []string{"*out"}, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on tenant - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple tenants if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com", "cgrates.org"}, nil, nil, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false, false); err != nil { + 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on tor if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call"}, - nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple tor if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call", "call"}, - nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on account if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1002"}, - nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple account if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "1002"}, - nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on subject if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000"}, - nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple subject if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000", "1002"}, - nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on destPrefix if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, []string{"+498651"}, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, nil, nil, []string{"+498651"}, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple destPrefixes if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "+498651"}, nil, nil, - 0, 0, timeStart, timeEnd, false, false, false); err != nil { + 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 4 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ratedAccount if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, []string{"8001"}, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, []string{"8001"}, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ratedSubject if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, []string{"91001"}, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, []string{"91001"}, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ignoreErr - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, true, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, true, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ignoreRated var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, true, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, true, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -453,41 +454,41 @@ func TestGetStoredCdrs(t *testing.T) { } } // Filter on orderIdStart - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on orderIdStart and orderIdEnd if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, orderIdEnd+1, timeStart, timeEnd, - false, false, false); err != nil { + false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on timeStart timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC) - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on timeStart and timeEnd timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC) - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Combined filter if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"rated"}, nil, nil, nil, nil, nil, - nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ignoreDerived - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, true); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, true, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { // ToDo: Recheck this value t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -503,7 +504,7 @@ func TestRemStoredCdrs(t *testing.T) { if err := mysqlDb.RemStoredCdrs([]string{cgrIdB1}); err != nil { t.Error(err.Error()) } - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 7 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -524,7 +525,7 @@ func TestRemStoredCdrs(t *testing.T) { cgrIdB2, cgrIdB3}); err != nil { t.Error(err.Error()) } - if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false, nil); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 0 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 2c7eec007..b309e15f3 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -40,7 +40,7 @@ type TPPagination struct { SearchTerm string } -func (pag *TPPagination) GetLimit() (low, high int) { +func (pag *TPPagination) GetLimits() (low, high int) { if pag.ItemsPerPage == 0 { return 0, math.MaxInt32 } @@ -582,6 +582,9 @@ type AttrGetCdrs struct { TimeEnd string // If provided, it will represent the end of the CDRs interval (<) SkipErrors bool // Do not export errored CDRs SkipRated bool // Do not export rated CDRs + Page int + ItemsPerPage int + SearchTerm string } type AttrRemCdrs struct {