influxdb/storage/retention_test.go

122 lines
3.3 KiB
Go
Raw Normal View History

2018-10-05 16:57:49 +00:00
package storage
import (
"context"
"math"
"math/rand"
"reflect"
"testing"
"time"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/tsdb"
2018-10-05 16:57:49 +00:00
)
func TestRetentionService(t *testing.T) {
2018-10-05 16:57:49 +00:00
engine := NewTestEngine()
service := newRetentionEnforcer(engine, NewTestBucketFinder())
2018-10-05 16:57:49 +00:00
now := time.Date(2018, 4, 10, 23, 12, 33, 0, time.UTC)
t.Run("no buckets", func(t *testing.T) {
2019-02-04 19:26:21 +00:00
service.expireData(nil, now)
service.expireData([]*platform.Bucket{}, now)
2018-10-05 16:57:49 +00:00
})
// Generate some buckets to expire
buckets := []*platform.Bucket{}
expMatched := map[string]struct{}{} // To be used for verifying test results.
expRejected := map[string]struct{}{} // To be used for verifying test results.
2018-10-05 16:57:49 +00:00
for i := 0; i < 15; i++ {
name := genMeasurementName()
var n [16]byte
copy(n[:], name)
orgID, bucketID := tsdb.DecodeName(n)
2018-10-05 16:57:49 +00:00
// Put 1/3rd in the rpByBucketID into the set to delete and 1/3rd into the set
// to not delete because no rp, and 1/3rd into the set to not delete because 0 rp.
if i%3 == 0 {
buckets = append(buckets, &platform.Bucket{
OrganizationID: orgID,
ID: bucketID,
RetentionPeriod: 3 * time.Hour,
})
expMatched[string(name)] = struct{}{}
2018-10-05 16:57:49 +00:00
} else if i%3 == 1 {
expRejected[string(name)] = struct{}{}
2018-10-05 16:57:49 +00:00
} else if i%3 == 2 {
buckets = append(buckets, &platform.Bucket{
OrganizationID: orgID,
ID: bucketID,
RetentionPeriod: 0,
})
expRejected[string(name)] = struct{}{}
2018-10-05 16:57:49 +00:00
}
}
gotMatched := map[string]struct{}{}
engine.DeleteBucketRangeFn = func(orgID, bucketID platform.ID, from, to int64) error {
if from != math.MinInt64 {
t.Fatalf("got from %d, expected %d", from, math.MinInt64)
}
wantTo := now.Add(-3 * time.Hour).UnixNano()
if to != wantTo {
t.Fatalf("got to %d, expected %d", to, wantTo)
2018-10-05 16:57:49 +00:00
}
name := tsdb.EncodeName(orgID, bucketID)
if _, ok := expRejected[string(name[:])]; ok {
t.Fatalf("got a delete for %x", name)
}
gotMatched[string(name[:])] = struct{}{}
2018-10-05 16:57:49 +00:00
return nil
}
t.Run("multiple buckets", func(t *testing.T) {
2019-02-04 19:26:21 +00:00
service.expireData(buckets, now)
if !reflect.DeepEqual(gotMatched, expMatched) {
t.Fatalf("got\n%#v\nexpected\n%#v", gotMatched, expMatched)
}
2018-10-05 16:57:49 +00:00
})
}
// genMeasurementName generates a random measurement name or panics.
func genMeasurementName() []byte {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
panic(err)
}
return b
}
type TestEngine struct {
DeleteBucketRangeFn func(platform.ID, platform.ID, int64, int64) error
2018-10-05 16:57:49 +00:00
}
func NewTestEngine() *TestEngine {
return &TestEngine{
DeleteBucketRangeFn: func(platform.ID, platform.ID, int64, int64) error { return nil },
2018-10-05 16:57:49 +00:00
}
}
func (e *TestEngine) DeleteBucketRange(orgID, bucketID platform.ID, min, max int64) error {
return e.DeleteBucketRangeFn(orgID, bucketID, min, max)
2018-10-05 16:57:49 +00:00
}
type TestBucketFinder struct {
2018-10-09 18:43:10 +00:00
FindBucketsFn func(context.Context, platform.BucketFilter, ...platform.FindOptions) ([]*platform.Bucket, int, error)
2018-10-05 16:57:49 +00:00
}
func NewTestBucketFinder() *TestBucketFinder {
return &TestBucketFinder{
2018-10-09 18:43:10 +00:00
FindBucketsFn: func(context.Context, platform.BucketFilter, ...platform.FindOptions) ([]*platform.Bucket, int, error) {
return nil, 0, nil
},
2018-10-05 16:57:49 +00:00
}
}
2018-10-09 18:43:10 +00:00
func (f *TestBucketFinder) FindBuckets(ctx context.Context, filter platform.BucketFilter, opts ...platform.FindOptions) ([]*platform.Bucket, int, error) {
return f.FindBucketsFn(ctx, filter, opts...)
2018-10-05 16:57:49 +00:00
}