122 lines
3.3 KiB
Go
122 lines
3.3 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"math/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
platform "github.com/influxdata/influxdb"
|
|
"github.com/influxdata/influxdb/tsdb"
|
|
)
|
|
|
|
func TestRetentionService(t *testing.T) {
|
|
engine := NewTestEngine()
|
|
service := newRetentionEnforcer(engine, NewTestBucketFinder())
|
|
now := time.Date(2018, 4, 10, 23, 12, 33, 0, time.UTC)
|
|
|
|
t.Run("no buckets", func(t *testing.T) {
|
|
service.expireData(nil, now)
|
|
service.expireData([]*platform.Bucket{}, now)
|
|
})
|
|
|
|
// 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.
|
|
for i := 0; i < 15; i++ {
|
|
name := genMeasurementName()
|
|
|
|
var n [16]byte
|
|
copy(n[:], name)
|
|
orgID, bucketID := tsdb.DecodeName(n)
|
|
|
|
// 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{}{}
|
|
} else if i%3 == 1 {
|
|
expRejected[string(name)] = struct{}{}
|
|
} else if i%3 == 2 {
|
|
buckets = append(buckets, &platform.Bucket{
|
|
OrganizationID: orgID,
|
|
ID: bucketID,
|
|
RetentionPeriod: 0,
|
|
})
|
|
expRejected[string(name)] = struct{}{}
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
name := tsdb.EncodeName(orgID, bucketID)
|
|
if _, ok := expRejected[string(name[:])]; ok {
|
|
t.Fatalf("got a delete for %x", name)
|
|
}
|
|
gotMatched[string(name[:])] = struct{}{}
|
|
return nil
|
|
}
|
|
|
|
t.Run("multiple buckets", func(t *testing.T) {
|
|
service.expireData(buckets, now)
|
|
if !reflect.DeepEqual(gotMatched, expMatched) {
|
|
t.Fatalf("got\n%#v\nexpected\n%#v", gotMatched, expMatched)
|
|
}
|
|
})
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func NewTestEngine() *TestEngine {
|
|
return &TestEngine{
|
|
DeleteBucketRangeFn: func(platform.ID, platform.ID, int64, int64) error { return nil },
|
|
}
|
|
}
|
|
|
|
func (e *TestEngine) DeleteBucketRange(orgID, bucketID platform.ID, min, max int64) error {
|
|
return e.DeleteBucketRangeFn(orgID, bucketID, min, max)
|
|
}
|
|
|
|
type TestBucketFinder struct {
|
|
FindBucketsFn func(context.Context, platform.BucketFilter, ...platform.FindOptions) ([]*platform.Bucket, int, error)
|
|
}
|
|
|
|
func NewTestBucketFinder() *TestBucketFinder {
|
|
return &TestBucketFinder{
|
|
FindBucketsFn: func(context.Context, platform.BucketFilter, ...platform.FindOptions) ([]*platform.Bucket, int, error) {
|
|
return nil, 0, nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func (f *TestBucketFinder) FindBuckets(ctx context.Context, filter platform.BucketFilter, opts ...platform.FindOptions) ([]*platform.Bucket, int, error) {
|
|
return f.FindBucketsFn(ctx, filter, opts...)
|
|
}
|