1
0
mirror of https://github.com/minio/minio.git synced 2025-04-11 23:12:12 -04:00
Krishnan Parthasarathi 01447d2438
Fix evaluation of NewerNoncurrentVersions ()
- Move VersionPurgeStatus into replication package
- ilm: Evaluate policy w/ obj retention/replication
- lifecycle: Use Evaluator to enforce ILM in scanner
- Unit tests covering ILM, replication and retention
- Simplify NewEvaluator constructor
2025-04-02 23:45:06 -07:00

178 lines
4.8 KiB
Go

// Copyright (c) 2015-2025 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package lifecycle
import (
"fmt"
"testing"
"time"
"github.com/google/uuid"
)
func TestNewerNoncurrentVersions(t *testing.T) {
prepLifecycleCfg := func(tagKeys []string, retainVersions []int) Lifecycle {
var lc Lifecycle
for i := range retainVersions {
ruleID := fmt.Sprintf("rule-%d", i)
tag := Tag{
Key: tagKeys[i],
Value: "minio",
}
lc.Rules = append(lc.Rules, Rule{
ID: ruleID,
Status: "Enabled",
Filter: Filter{
Tag: tag,
set: true,
},
NoncurrentVersionExpiration: NoncurrentVersionExpiration{
NewerNoncurrentVersions: retainVersions[i],
set: true,
},
})
}
return lc
}
lc := prepLifecycleCfg([]string{"tag3", "tag4", "tag5"}, []int{3, 4, 5})
evaluator := NewEvaluator(lc)
tagKeys := []string{"tag3", "tag3", "tag3", "tag4", "tag4", "tag5", "tag5"}
verIDs := []string{
"0NdAikoUVNGEpCUuB9vl.XyoMftMXCSg", "19M6Z405yFZuYygnnU9jKzsOBamTZK_7", "0PmlJdFWi_9d6l_dAkWrrhP.bBgtFk6V", // spellchecker:disable-line
".MmRalFNNJyOLymgCtQ3.qsdoYpy8qkB", "Bjb4OlMW9Agx.Nrggh15iU6frGu2CLde", "ngBmUd_cVl6ckONI9XsKGpJjzimohrzZ", // spellchecker:disable-line
"T6m1heTHLUtnByW2IOWJ3zM4JP9xXt2O", // spellchecker:disable-line
}
wantEvents := []Event{
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: DeleteVersionAction},
}
var objs []ObjectOpts
curModTime := time.Date(2025, time.February, 10, 23, 0, 0, 0, time.UTC)
for i := range tagKeys {
obj := ObjectOpts{
Name: "obj",
VersionID: verIDs[i],
ModTime: curModTime.Add(time.Duration(-i) * time.Second),
UserTags: fmt.Sprintf("%s=minio", tagKeys[i]),
NumVersions: len(verIDs),
}
if i == 0 {
obj.IsLatest = true
} else {
obj.SuccessorModTime = curModTime.Add(time.Duration(-i+1) * time.Second)
}
objs = append(objs, obj)
}
now := time.Date(2025, time.February, 10, 23, 0, 0, 0, time.UTC)
gotEvents := evaluator.eval(objs, now)
for i := range wantEvents {
if gotEvents[i].Action != wantEvents[i].Action {
t.Fatalf("got %v, want %v", gotEvents[i], wantEvents[i])
}
}
lc = prepLifecycleCfg([]string{"tag3", "tag4", "tag5"}, []int{1, 2, 3})
objs = objs[:len(objs)-1]
wantEvents = []Event{
{Action: NoneAction},
{Action: NoneAction},
{Action: DeleteVersionAction},
{Action: NoneAction},
{Action: DeleteVersionAction},
{Action: NoneAction},
}
evaluator = NewEvaluator(lc)
gotEvents = evaluator.eval(objs, now)
for i := range wantEvents {
if gotEvents[i].Action != wantEvents[i].Action {
t.Fatalf("test-%d: got %v, want %v", i+1, gotEvents[i], wantEvents[i])
}
}
lc = Lifecycle{
Rules: []Rule{
{
ID: "AllVersionsExpiration",
Status: "Enabled",
Filter: Filter{},
Expiration: Expiration{
Days: 1,
DeleteAll: Boolean{
val: true,
set: true,
},
set: true,
},
},
},
}
now = time.Date(2025, time.February, 12, 23, 0, 0, 0, time.UTC)
evaluator = NewEvaluator(lc)
gotEvents = evaluator.eval(objs, now)
wantEvents = []Event{
{Action: DeleteAllVersionsAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
{Action: NoneAction},
}
for i := range wantEvents {
if gotEvents[i].Action != wantEvents[i].Action {
t.Fatalf("test-%d: got %v, want %v", i+1, gotEvents[i], wantEvents[i])
}
}
}
func TestEmptyEvaluator(t *testing.T) {
var objs []ObjectOpts
curModTime := time.Date(2025, time.February, 10, 23, 0, 0, 0, time.UTC)
for i := range 5 {
obj := ObjectOpts{
Name: "obj",
VersionID: uuid.New().String(),
ModTime: curModTime.Add(time.Duration(-i) * time.Second),
NumVersions: 5,
}
if i == 0 {
obj.IsLatest = true
} else {
obj.SuccessorModTime = curModTime.Add(time.Duration(-i+1) * time.Second)
}
objs = append(objs, obj)
}
evaluator := NewEvaluator(Lifecycle{})
events, err := evaluator.Eval(objs)
if err != nil {
t.Fatal(err)
}
for _, event := range events {
if event.Action != NoneAction {
t.Fatalf("got %v, want %v", event.Action, NoneAction)
}
}
}