zrepl/internal/pruning/retentiongrid/retentiongrid_test.go

186 lines
5.0 KiB
Go
Raw Permalink Normal View History

2018-08-26 19:20:08 +02:00
package retentiongrid
2017-06-21 20:29:20 +02:00
import (
"fmt"
"strconv"
"strings"
"testing"
"time"
2019-03-22 19:41:12 +01:00
"github.com/stretchr/testify/assert"
2017-06-21 20:29:20 +02:00
)
type testInterval struct {
2018-08-26 19:20:08 +02:00
length time.Duration
keepCount int
}
func (i *testInterval) Length() time.Duration { return i.length }
func (i *testInterval) KeepCount() int { return i.keepCount }
2018-08-26 19:20:08 +02:00
2018-09-24 17:30:03 +02:00
func gridFromString(gs string) (g *Grid) {
sintervals := strings.Split(gs, "|")
intervals := make([]Interval, len(sintervals))
for idx, i := range sintervals {
2017-06-21 20:29:20 +02:00
comps := strings.SplitN(i, ",", 2)
var durationStr, numSnapsStr string
durationStr = comps[0]
if len(comps) == 1 {
numSnapsStr = "1"
} else {
numSnapsStr = comps[1]
}
var err error
var interval testInterval
2017-06-21 20:29:20 +02:00
2018-08-26 19:20:08 +02:00
if interval.keepCount, err = strconv.Atoi(numSnapsStr); err != nil {
2017-06-21 20:29:20 +02:00
panic(err)
}
2018-08-26 19:20:08 +02:00
if interval.length, err = time.ParseDuration(durationStr); err != nil {
2017-06-21 20:29:20 +02:00
panic(err)
}
intervals[idx] = &interval
2017-06-21 20:29:20 +02:00
}
return NewGrid(intervals)
2017-06-21 20:29:20 +02:00
}
type testSnap struct {
2017-06-21 20:29:20 +02:00
Name string
ShouldKeep bool
date time.Time
}
func (ds testSnap) Date() time.Time { return ds.date }
2017-06-21 20:29:20 +02:00
2018-09-24 17:30:03 +02:00
func validateRetentionGridFitEntries(t *testing.T, now time.Time, input, keep, remove []Entry) {
2017-06-21 20:29:20 +02:00
snapDescr := func(d testSnap) string {
2017-06-21 20:29:20 +02:00
return fmt.Sprintf("%s@%s", d.Name, d.date.Sub(now))
}
t.Logf("keep list:\n")
for k := range keep {
t.Logf("\t%s\n", snapDescr(keep[k].(testSnap)))
2017-06-21 20:29:20 +02:00
}
t.Logf("remove list:\n")
for k := range remove {
t.Logf("\t%s\n", snapDescr(remove[k].(testSnap)))
2017-06-21 20:29:20 +02:00
}
t.Logf("\n\n")
for _, s := range input {
d := s.(testSnap)
2017-06-21 20:29:20 +02:00
descr := snapDescr(d)
t.Logf("testing %s\n", descr)
if d.ShouldKeep {
assert.Contains(t, keep, d, "expecting %s to be kept", descr)
} else {
assert.Contains(t, remove, d, "expecting %s to be removed", descr)
}
}
t.Logf("resulting list:\n")
for k := range keep {
t.Logf("\t%s\n", snapDescr(keep[k].(testSnap)))
2017-06-21 20:29:20 +02:00
}
}
func TestEmptyInput(t *testing.T) {
2018-09-24 17:30:03 +02:00
g := gridFromString("10m|10m|10m|1h")
keep, remove := g.FitEntries([]Entry{})
2017-06-21 20:29:20 +02:00
assert.Empty(t, keep)
assert.Empty(t, remove)
}
func TestIntervalBoundariesAndAlignment(t *testing.T) {
2018-09-24 17:30:03 +02:00
g := gridFromString("10m|10m|10m")
2017-06-21 20:29:20 +02:00
t.Logf("%#v\n", g)
now := time.Unix(0, 0)
2018-09-24 17:30:03 +02:00
snaps := []Entry{
testSnap{"0", true, now.Add(1 * time.Minute)}, // before now => keep unconditionally
testSnap{"1", true, now}, // 1st interval left edge => inclusive
testSnap{"2", true, now.Add(-10 * time.Minute)}, // 2nd interval left edge => inclusive
testSnap{"3", true, now.Add(-20 * time.Minute)}, // 3rd interval left edge => inclusuive
testSnap{"4", false, now.Add(-30 * time.Minute)}, // 3rd interval right edge => excludive
testSnap{"5", false, now.Add(-40 * time.Minute)}, // after last interval => remove unconditionally
}
keep, remove := g.fitEntriesWithNow(now, snaps)
validateRetentionGridFitEntries(t, now, snaps, keep, remove)
}
func TestKeepsOldestSnapsInABucket(t *testing.T) {
g := gridFromString("1m,2")
relt := func(secs int64) time.Time { return time.Unix(secs, 0) }
snaps := []Entry{
testSnap{"1", true, relt(1)},
testSnap{"2", true, relt(2)},
testSnap{"3", false, relt(3)},
testSnap{"4", false, relt(4)},
testSnap{"5", false, relt(5)},
2017-06-21 20:29:20 +02:00
}
now := relt(6)
keep, remove := g.FitEntries(snaps)
2017-06-21 20:29:20 +02:00
validateRetentionGridFitEntries(t, now, snaps, keep, remove)
}
2017-06-21 20:29:20 +02:00
func TestRespectsKeepCountAll(t *testing.T) {
g := gridFromString("1m,-1|1m,1")
relt := func(secs int64) time.Time { return time.Unix(secs, 0) }
snaps := []Entry{
testSnap{"a", true, relt(0)},
testSnap{"b", true, relt(-1)},
testSnap{"c", true, relt(-2)},
testSnap{"d", false, relt(-60)},
testSnap{"e", true, relt(-61)},
}
keep, remove := g.FitEntries(snaps)
validateRetentionGridFitEntries(t, relt(61), snaps, keep, remove)
2017-06-21 20:29:20 +02:00
}
func TestComplex(t *testing.T) {
2017-06-21 20:29:20 +02:00
2018-09-24 17:30:03 +02:00
g := gridFromString("10m,-1|10m|10m,2|1h")
2017-06-21 20:29:20 +02:00
t.Logf("%#v\n", g)
now := time.Unix(0, 0)
2018-09-24 17:30:03 +02:00
snaps := []Entry{
// pre-now must always be kept
testSnap{"1", true, now.Add(3 * time.Minute)},
// 1st interval allows unlimited entries
testSnap{"b1", true, now.Add(-6 * time.Minute)},
testSnap{"b3", true, now.Add(-8 * time.Minute)},
testSnap{"b2", true, now.Add(-9 * time.Minute)},
// 2nd interval allows 1 entry
testSnap{"a", false, now.Add(-11 * time.Minute)},
testSnap{"c", true, now.Add(-19 * time.Minute)},
// 3rd interval allows 2 entries
testSnap{"foo", true, now.Add(-25 * time.Minute)},
testSnap{"bar", true, now.Add(-26 * time.Minute)},
// this is at the left edge of the 4th interval
testSnap{"border", false, now.Add(-30 * time.Minute)},
// right in the 4th interval
testSnap{"d", true, now.Add(-1*time.Hour - 15*time.Minute)},
// on the right edge of 4th interval => not in it => delete
testSnap{"q", false, now.Add(-1*time.Hour - 30*time.Minute)},
// older then 4th interval => always delete
testSnap{"e", false, now.Add(-1*time.Hour - 31*time.Minute)},
testSnap{"f", false, now.Add(-2 * time.Hour)},
2017-06-21 20:29:20 +02:00
}
keep, remove := g.fitEntriesWithNow(now, snaps)
2017-06-21 20:29:20 +02:00
validateRetentionGridFitEntries(t, now, snaps, keep, remove)
}