From 4ecbe749e45b4335e7426a493ab21c1fbe9e79cf Mon Sep 17 00:00:00 2001 From: Nathan Lowe Date: Tue, 9 Jul 2019 23:23:35 -0400 Subject: [PATCH 1/2] Retention: Implement Filter: Keep Latest K Signed-off-by: Nathan Lowe --- .../policy/rule/latestk/evaluator.go | 10 +++- .../policy/rule/latestk/evaluator_test.go | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/pkg/retention/policy/rule/latestk/evaluator_test.go diff --git a/src/pkg/retention/policy/rule/latestk/evaluator.go b/src/pkg/retention/policy/rule/latestk/evaluator.go index a49c5e1cc..cd4f137cd 100644 --- a/src/pkg/retention/policy/rule/latestk/evaluator.go +++ b/src/pkg/retention/policy/rule/latestk/evaluator.go @@ -38,8 +38,12 @@ type evaluator struct { // Process the candidates based on the rule definition func (e *evaluator) Process(artifacts []*res.Candidate) ([]*res.Candidate, error) { - // TODO: REPLACE SAMPLE CODE WITH REAL IMPLEMENTATION - return artifacts, nil + i := e.k + if i > len(artifacts) { + i = len(artifacts) + } + + return artifacts[:i], nil } // Specify what action is performed to the candidates processed by this evaluator @@ -51,7 +55,7 @@ func (e *evaluator) Action() string { func New(params rule.Parameters) rule.Evaluator { if params != nil { if param, ok := params[ParameterK]; ok { - if v, ok := param.(int); ok { + if v, ok := param.(int); ok && v >= 0 { return &evaluator{ k: v, } diff --git a/src/pkg/retention/policy/rule/latestk/evaluator_test.go b/src/pkg/retention/policy/rule/latestk/evaluator_test.go new file mode 100644 index 000000000..e88a2f49c --- /dev/null +++ b/src/pkg/retention/policy/rule/latestk/evaluator_test.go @@ -0,0 +1,57 @@ +package latestk + +import ( + "strconv" + "testing" + + "github.com/goharbor/harbor/src/pkg/retention/policy/rule" + "github.com/goharbor/harbor/src/pkg/retention/res" + "github.com/stretchr/testify/require" +) + +func TestEvaluator_New(t *testing.T) { + tests := []struct { + Name string + args rule.Parameters + expectedK int + }{ + {Name: "Valid", args: map[string]rule.Parameter{ParameterK: 5}, expectedK: 5}, + {Name: "Default If Negative", args: map[string]rule.Parameter{ParameterK: -1}, expectedK: DefaultK}, + {Name: "Default If Not Set", args: map[string]rule.Parameter{}, expectedK: DefaultK}, + {Name: "Default If Wrong Type", args: map[string]rule.Parameter{ParameterK: "foo"}, expectedK: DefaultK}, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + e := New(tt.args).(*evaluator) + + require.Equal(t, tt.expectedK, e.k) + }) + } +} + +func TestEvaluator_Process(t *testing.T) { + data := []*res.Candidate{{}, {}, {}, {}, {}} + + tests := []struct { + k int + expected int + }{ + {k: 0, expected: 0}, + {k: 1, expected: 1}, + {k: 3, expected: 3}, + {k: 5, expected: 5}, + {k: 6, expected: 5}, + } + + for _, tt := range tests { + t.Run(strconv.Itoa(tt.k), func(t *testing.T) { + e := New(map[string]rule.Parameter{ParameterK: tt.k}) + + result, err := e.Process(data) + + require.NoError(t, err) + require.Len(t, result, tt.expected) + }) + } +} From d7e6b1b62152d3781fb6d59abb90a63b3dafc6a6 Mon Sep 17 00:00:00 2001 From: Nathan Lowe Date: Sun, 14 Jul 2019 22:45:36 -0400 Subject: [PATCH 2/2] Sort artifacts before processing and port tests to github.com/stretchr/testify/suite Signed-off-by: Nathan Lowe --- .../policy/rule/latestk/evaluator.go | 7 ++++++ .../policy/rule/latestk/evaluator_test.go | 24 +++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/pkg/retention/policy/rule/latestk/evaluator.go b/src/pkg/retention/policy/rule/latestk/evaluator.go index cd4f137cd..8a270c938 100644 --- a/src/pkg/retention/policy/rule/latestk/evaluator.go +++ b/src/pkg/retention/policy/rule/latestk/evaluator.go @@ -15,6 +15,8 @@ package latestk import ( + "sort" + "github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/pkg/retention/policy/action" "github.com/goharbor/harbor/src/pkg/retention/policy/rule" @@ -38,6 +40,11 @@ type evaluator struct { // Process the candidates based on the rule definition func (e *evaluator) Process(artifacts []*res.Candidate) ([]*res.Candidate, error) { + // The updated proposal does not guarantee the order artifacts are provided, so we have to sort them first + sort.Slice(artifacts, func(i, j int) bool { + return artifacts[i].PushedTime < artifacts[j].PushedTime + }) + i := e.k if i > len(artifacts) { i = len(artifacts) diff --git a/src/pkg/retention/policy/rule/latestk/evaluator_test.go b/src/pkg/retention/policy/rule/latestk/evaluator_test.go index e88a2f49c..156eb605b 100644 --- a/src/pkg/retention/policy/rule/latestk/evaluator_test.go +++ b/src/pkg/retention/policy/rule/latestk/evaluator_test.go @@ -1,15 +1,22 @@ package latestk import ( + "math/rand" "strconv" "testing" + "github.com/stretchr/testify/suite" + "github.com/goharbor/harbor/src/pkg/retention/policy/rule" "github.com/goharbor/harbor/src/pkg/retention/res" "github.com/stretchr/testify/require" ) -func TestEvaluator_New(t *testing.T) { +type EvaluatorTestSuite struct { + suite.Suite +} + +func (e *EvaluatorTestSuite) TestNew() { tests := []struct { Name string args rule.Parameters @@ -22,7 +29,7 @@ func TestEvaluator_New(t *testing.T) { } for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { + e.T().Run(tt.Name, func(t *testing.T) { e := New(tt.args).(*evaluator) require.Equal(t, tt.expectedK, e.k) @@ -30,8 +37,11 @@ func TestEvaluator_New(t *testing.T) { } } -func TestEvaluator_Process(t *testing.T) { - data := []*res.Candidate{{}, {}, {}, {}, {}} +func (e *EvaluatorTestSuite) TestProcess() { + data := []*res.Candidate{{PushedTime: 0}, {PushedTime: 1}, {PushedTime: 2}, {PushedTime: 3}, {PushedTime: 4}} + rand.Shuffle(len(data), func(i, j int) { + data[i], data[j] = data[j], data[i] + }) tests := []struct { k int @@ -45,7 +55,7 @@ func TestEvaluator_Process(t *testing.T) { } for _, tt := range tests { - t.Run(strconv.Itoa(tt.k), func(t *testing.T) { + e.T().Run(strconv.Itoa(tt.k), func(t *testing.T) { e := New(map[string]rule.Parameter{ParameterK: tt.k}) result, err := e.Process(data) @@ -55,3 +65,7 @@ func TestEvaluator_Process(t *testing.T) { }) } } + +func TestEvaluator(t *testing.T) { + suite.Run(t, &EvaluatorTestSuite{}) +}