mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-25 01:44:43 +01:00
pruning: fix tests + implement 'not_replicated' and 'keep_regex' keep rule
tests expected that a KeepRule returns a *keep* list whereas it actually returns a *destroy* list.
This commit is contained in:
parent
a2aa8e7bd7
commit
d684302864
@ -188,7 +188,7 @@ func parseKeepRule(in config.PruningEnum) (p PrunePolicy, err error) {
|
|||||||
case config.PruneGrid:
|
case config.PruneGrid:
|
||||||
return retentiongrid.ParseGridPrunePolicy(v, willSeeBookmarks)
|
return retentiongrid.ParseGridPrunePolicy(v, willSeeBookmarks)
|
||||||
//case config.PruneKeepLastN:
|
//case config.PruneKeepLastN:
|
||||||
//case config.PruneKeepPrefix:
|
//case config.PruneKeepRegex:
|
||||||
//case config.PruneKeepNotReplicated:
|
//case config.PruneKeepNotReplicated:
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unknown keep rule type %v", v))
|
panic(fmt.Sprintf("unknown keep rule type %v", v))
|
||||||
|
@ -179,9 +179,9 @@ type PruneKeepLastN struct {
|
|||||||
Count int `yaml:"count"`
|
Count int `yaml:"count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PruneKeepPrefix struct { // FIXME rename to KeepPrefix
|
type PruneKeepRegex struct { // FIXME rename to KeepRegex
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Prefix string `yaml:"prefix"`
|
Regex string `yaml:"prefix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoggingOutletEnum struct {
|
type LoggingOutletEnum struct {
|
||||||
@ -301,7 +301,7 @@ func (t *PruningEnum) UnmarshalYAML(u func(interface{}, bool) error) (err error)
|
|||||||
"not_replicated": &PruneKeepNotReplicated{},
|
"not_replicated": &PruneKeepNotReplicated{},
|
||||||
"last_n": &PruneKeepLastN{},
|
"last_n": &PruneKeepLastN{},
|
||||||
"grid": &PruneGrid{},
|
"grid": &PruneGrid{},
|
||||||
"prefix": &PruneKeepPrefix{},
|
"prefix": &PruneKeepRegex{},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ func NewKeepLastN(n int) (*KeepLastN, error) {
|
|||||||
return &KeepLastN{n}, nil
|
return &KeepLastN{n}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KeepLastN) KeepRule(snaps []Snapshot) []Snapshot {
|
func (k KeepLastN) KeepRule(snaps []Snapshot) (destroyList []Snapshot) {
|
||||||
|
|
||||||
if k.n > len(snaps) {
|
if k.n > len(snaps) {
|
||||||
return snaps
|
return []Snapshot{}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := shallowCopySnapList(snaps)
|
res := shallowCopySnapList(snaps)
|
||||||
@ -28,5 +28,5 @@ func (k KeepLastN) KeepRule(snaps []Snapshot) []Snapshot {
|
|||||||
return res[i].Date().After(res[j].Date())
|
return res[i].Date().After(res[j].Date())
|
||||||
})
|
})
|
||||||
|
|
||||||
return res[:k.n]
|
return res[k.n:]
|
||||||
}
|
}
|
||||||
|
@ -29,17 +29,18 @@ func TestKeepLastN(t *testing.T) {
|
|||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
KeepLastN{2},
|
KeepLastN{2},
|
||||||
},
|
},
|
||||||
exp: map[string]bool{
|
expDestroy: map[string]bool{
|
||||||
"4": true, "5": true,
|
"1": true, "2": true, "3": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"keep1": { // Keep one of two with same time
|
"keep1OfTwoWithSameTime": { // Keep one of two with same time
|
||||||
inputs: inputs["s1"],
|
inputs: inputs["s1"],
|
||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
KeepLastN{1},
|
KeepLastN{1},
|
||||||
},
|
},
|
||||||
exp: map[string]bool{
|
expDestroyAlternatives: []map[string]bool{
|
||||||
"4": true, //5 would be ok too
|
{"1": true, "2": true, "3": true, "4": true},
|
||||||
|
{"1": true, "2": true, "3": true, "5": true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"keepMany": {
|
"keepMany": {
|
||||||
@ -47,20 +48,14 @@ func TestKeepLastN(t *testing.T) {
|
|||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
KeepLastN{100},
|
KeepLastN{100},
|
||||||
},
|
},
|
||||||
exp: map[string]bool{
|
expDestroy: map[string]bool{},
|
||||||
"1": true,
|
|
||||||
"2": true,
|
|
||||||
"3": true,
|
|
||||||
"4": true,
|
|
||||||
"5": true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"empty": {
|
"empty": {
|
||||||
inputs: inputs["s2"],
|
inputs: inputs["s2"],
|
||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
KeepLastN{100},
|
KeepLastN{100},
|
||||||
},
|
},
|
||||||
exp: map[string]bool{},
|
expDestroy: map[string]bool{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
15
pruning/keep_not_replicated.go
Normal file
15
pruning/keep_not_replicated.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package pruning
|
||||||
|
|
||||||
|
type KeepNotReplicated struct {
|
||||||
|
forceConstructor struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*KeepNotReplicated) KeepRule(snaps []Snapshot) (destroyList []Snapshot) {
|
||||||
|
return filterSnapList(snaps, func(snapshot Snapshot) bool {
|
||||||
|
return snapshot.Replicated()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKeepNotReplicated() *KeepNotReplicated {
|
||||||
|
return &KeepNotReplicated{}
|
||||||
|
}
|
39
pruning/keep_not_replicated_test.go
Normal file
39
pruning/keep_not_replicated_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package pruning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewKeepNotReplicated(t *testing.T) {
|
||||||
|
|
||||||
|
inputs := map[string][]Snapshot{
|
||||||
|
"s1": []Snapshot{
|
||||||
|
stubSnap{name: "1", replicated: true},
|
||||||
|
stubSnap{name: "2", replicated: false},
|
||||||
|
stubSnap{name: "3", replicated: true},
|
||||||
|
},
|
||||||
|
"s2": []Snapshot{},
|
||||||
|
}
|
||||||
|
|
||||||
|
tcs := map[string]testCase{
|
||||||
|
"destroysOnlyReplicated": {
|
||||||
|
inputs: inputs["s1"],
|
||||||
|
rules: []KeepRule{
|
||||||
|
NewKeepNotReplicated(),
|
||||||
|
},
|
||||||
|
expDestroy: map[string]bool{
|
||||||
|
"1": true, "3": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
inputs: inputs["s2"],
|
||||||
|
rules: []KeepRule{
|
||||||
|
NewKeepNotReplicated(),
|
||||||
|
},
|
||||||
|
expDestroy: map[string]bool{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testTable(tcs, t)
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package pruning
|
package pruning
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zrepl/zrepl/config"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeepRule interface {
|
type KeepRule interface {
|
||||||
KeepRule(snaps []Snapshot) []Snapshot
|
KeepRule(snaps []Snapshot) (destroyList []Snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Snapshot interface {
|
type Snapshot interface {
|
||||||
@ -17,8 +20,8 @@ type Snapshot interface {
|
|||||||
// The returned snapshot list is guaranteed to only contains elements of input parameter snaps
|
// The returned snapshot list is guaranteed to only contains elements of input parameter snaps
|
||||||
func PruneSnapshots(snaps []Snapshot, keepRules []KeepRule) []Snapshot {
|
func PruneSnapshots(snaps []Snapshot, keepRules []KeepRule) []Snapshot {
|
||||||
|
|
||||||
if len(keepRules) == 0 {
|
if keepRules == nil || len(keepRules) == 0 {
|
||||||
return snaps
|
return []Snapshot{}
|
||||||
}
|
}
|
||||||
|
|
||||||
remCount := make(map[Snapshot]int, len(snaps))
|
remCount := make(map[Snapshot]int, len(snaps))
|
||||||
@ -38,3 +41,27 @@ func PruneSnapshots(snaps []Snapshot, keepRules []KeepRule) []Snapshot {
|
|||||||
|
|
||||||
return remove
|
return remove
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RulesFromConfig(in []config.PruningEnum) (rules []KeepRule, err error) {
|
||||||
|
rules = make([]KeepRule, len(in))
|
||||||
|
for i := range in {
|
||||||
|
rules[i], err = RuleFromConfig(in[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "cannot build rule #%d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RuleFromConfig(in config.PruningEnum) (KeepRule, error) {
|
||||||
|
switch v := in.Ret.(type) {
|
||||||
|
case *config.PruneKeepNotReplicated:
|
||||||
|
return NewKeepNotReplicated(), nil
|
||||||
|
case *config.PruneKeepLastN:
|
||||||
|
return NewKeepLastN(v.Count)
|
||||||
|
case *config.PruneKeepRegex:
|
||||||
|
return NewKeepRegex(v.Regex)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown keep rule type %T", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package pruning
|
package pruning
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -20,9 +18,10 @@ func (s stubSnap) Replicated() bool { return s.replicated }
|
|||||||
func (s stubSnap) Date() time.Time { return s.date }
|
func (s stubSnap) Date() time.Time { return s.date }
|
||||||
|
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
inputs []Snapshot
|
inputs []Snapshot
|
||||||
rules []KeepRule
|
rules []KeepRule
|
||||||
exp, eff map[string]bool
|
expDestroy, effDestroy map[string]bool
|
||||||
|
expDestroyAlternatives []map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTable(tcs map[string]testCase, t *testing.T) {
|
func testTable(tcs map[string]testCase, t *testing.T) {
|
||||||
@ -42,11 +41,26 @@ func testTable(tcs map[string]testCase, t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
tc := tcs[name]
|
tc := tcs[name]
|
||||||
remove := PruneSnapshots(tc.inputs, tc.rules)
|
remove := PruneSnapshots(tc.inputs, tc.rules)
|
||||||
tc.eff = make(map[string]bool)
|
tc.effDestroy = make(map[string]bool)
|
||||||
for _, s := range remove {
|
for _, s := range remove {
|
||||||
tc.eff[s.Name()] = true
|
tc.effDestroy[s.Name()] = true
|
||||||
|
}
|
||||||
|
if tc.expDestroyAlternatives == nil {
|
||||||
|
if tc.expDestroy == nil {
|
||||||
|
panic("must specify either expDestroyAlternatives or expDestroy")
|
||||||
|
}
|
||||||
|
tc.expDestroyAlternatives = []map[string]bool{tc.expDestroy}
|
||||||
|
}
|
||||||
|
var okAlt map[string]bool = nil
|
||||||
|
for _, alt := range tc.expDestroyAlternatives {
|
||||||
|
t.Logf("testing possible result: %v", alt)
|
||||||
|
if mapEqual(alt, tc.effDestroy) {
|
||||||
|
okAlt = alt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if okAlt == nil {
|
||||||
|
t.Errorf("no alternatives matched result: %v", tc.effDestroy)
|
||||||
}
|
}
|
||||||
assert.True(t, mapEqual(tc.exp, tc.eff), fmt.Sprintf("is %v but should be %v", tc.eff, tc.exp))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +81,7 @@ func TestPruneSnapshots(t *testing.T) {
|
|||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
MustKeepRegex("foo_"),
|
MustKeepRegex("foo_"),
|
||||||
},
|
},
|
||||||
exp: map[string]bool{
|
expDestroy: map[string]bool{
|
||||||
"bar_123": true,
|
"bar_123": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -77,7 +91,7 @@ func TestPruneSnapshots(t *testing.T) {
|
|||||||
MustKeepRegex("foo_"),
|
MustKeepRegex("foo_"),
|
||||||
MustKeepRegex("bar_"),
|
MustKeepRegex("bar_"),
|
||||||
},
|
},
|
||||||
exp: map[string]bool{},
|
expDestroy: map[string]bool{},
|
||||||
},
|
},
|
||||||
"onlyThoseRemovedByAllAreRemoved": {
|
"onlyThoseRemovedByAllAreRemoved": {
|
||||||
inputs: inputs["s1"],
|
inputs: inputs["s1"],
|
||||||
@ -85,26 +99,27 @@ func TestPruneSnapshots(t *testing.T) {
|
|||||||
MustKeepRegex("notInS1"), // would remove all
|
MustKeepRegex("notInS1"), // would remove all
|
||||||
MustKeepRegex("bar_"), // would remove all but bar_, i.e. foo_.*
|
MustKeepRegex("bar_"), // would remove all but bar_, i.e. foo_.*
|
||||||
},
|
},
|
||||||
exp: map[string]bool{
|
expDestroy: map[string]bool{
|
||||||
"foo_123": true,
|
"foo_123": true,
|
||||||
"foo_456": true,
|
"foo_456": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"noRulesKeepsAll": {
|
"noRulesKeepsAll": {
|
||||||
inputs: inputs["s1"],
|
inputs: inputs["s1"],
|
||||||
rules: []KeepRule{},
|
rules: []KeepRule{},
|
||||||
exp: map[string]bool{
|
expDestroy: map[string]bool{},
|
||||||
"foo_123": true,
|
},
|
||||||
"foo_456": true,
|
"nilRulesKeepsAll": {
|
||||||
"bar_123": true,
|
inputs: inputs["s1"],
|
||||||
},
|
rules: nil,
|
||||||
|
expDestroy: map[string]bool{},
|
||||||
},
|
},
|
||||||
"noSnaps": {
|
"noSnaps": {
|
||||||
inputs: []Snapshot{},
|
inputs: []Snapshot{},
|
||||||
rules: []KeepRule{
|
rules: []KeepRule{
|
||||||
MustKeepRegex("foo_"),
|
MustKeepRegex("foo_"),
|
||||||
},
|
},
|
||||||
exp: map[string]bool{},
|
expDestroy: map[string]bool{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user