diff --git a/internal/bucket/lifecycle/filter.go b/internal/bucket/lifecycle/filter.go index 68449fa6e..446397a50 100644 --- a/internal/bucket/lifecycle/filter.go +++ b/internal/bucket/lifecycle/filter.go @@ -232,21 +232,20 @@ func (f Filter) TestTags(userTags string) bool { } tagsMap := parsedTags.ToMap() - // This filter has tags configured but this object - // does not have any tag, skip this object - if len(tagsMap) == 0 { + // Not enough tags on object to satisfy the rule filter's tags + if len(tagsMap) < len(f.cachedTags) { return false } - // Both filter and object have tags, find a match, - // skip this object otherwise + var mismatch bool for k, cv := range f.cachedTags { v, ok := tagsMap[k] - if ok && v == cv { - return true + if !ok || v != cv { + mismatch = true + break } } - return false + return !mismatch } // BySize returns true if sz satisfies one of ObjectSizeGreaterThan, diff --git a/internal/bucket/lifecycle/filter_test.go b/internal/bucket/lifecycle/filter_test.go index f1ad691aa..31de24a10 100644 --- a/internal/bucket/lifecycle/filter_test.go +++ b/internal/bucket/lifecycle/filter_test.go @@ -241,3 +241,103 @@ func TestObjectSizeFilters(t *testing.T) { }) } } + +func TestTestTags(t *testing.T) { + noTags := Filter{ + set: true, + And: And{ + Tags: []Tag{}, + }, + andSet: true, + } + + oneTag := Filter{ + set: true, + And: And{ + Tags: []Tag{{Key: "FOO", Value: "1"}}, + }, + andSet: true, + } + + twoTags := Filter{ + set: true, + And: And{ + Tags: []Tag{{Key: "FOO", Value: "1"}, {Key: "BAR", Value: "2"}}, + }, + andSet: true, + } + + tests := []struct { + filter Filter + userTags string + want bool + }{ + { + filter: noTags, + userTags: "", + want: true, + }, + { + filter: noTags, + userTags: "A=3", + want: true, + }, + { + filter: oneTag, + userTags: "A=3", + want: false, + }, + { + filter: oneTag, + userTags: "FOO=1", + want: true, + }, + { + filter: oneTag, + userTags: "A=B&FOO=1", + want: true, + }, + { + filter: twoTags, + userTags: "", + want: false, + }, + { + filter: twoTags, + userTags: "FOO=1", + want: false, + }, + { + filter: twoTags, + userTags: "BAR=2", + want: false, + }, + { + filter: twoTags, + userTags: "FOO=2&BAR=2", + want: false, + }, + { + filter: twoTags, + userTags: "F=1&B=2", + want: false, + }, + { + filter: twoTags, + userTags: "FOO=1&BAR=2", + want: true, + }, + { + filter: twoTags, + userTags: "BAR=2&FOO=1", + want: true, + }, + } + for i, test := range tests { + t.Run(fmt.Sprintf("Test %d", i+1), func(t *testing.T) { + if got := test.filter.TestTags(test.userTags); got != test.want { + t.Errorf("Expected %v but got %v", test.want, got) + } + }) + } +}