github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/data-scanner_test.go (about) 1 // Copyright (c) 2015-2023 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "encoding/xml" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/google/uuid" 28 "github.com/minio/minio/internal/bucket/lifecycle" 29 "github.com/minio/minio/internal/bucket/versioning" 30 ) 31 32 func TestApplyNewerNoncurrentVersionsLimit(t *testing.T) { 33 objAPI, disks, err := prepareErasure(context.Background(), 8) 34 if err != nil { 35 t.Fatalf("Failed to initialize object layer: %v", err) 36 } 37 defer removeRoots(disks) 38 setObjectLayer(objAPI) 39 globalBucketMetadataSys = NewBucketMetadataSys() 40 globalBucketObjectLockSys = &BucketObjectLockSys{} 41 globalBucketVersioningSys = &BucketVersioningSys{} 42 es := newExpiryState(context.Background(), objAPI, 0) 43 workers := []chan expiryOp{make(chan expiryOp)} 44 es.workers.Store(&workers) 45 globalExpiryState = es 46 var wg sync.WaitGroup 47 wg.Add(1) 48 expired := make([]ObjectToDelete, 0, 5) 49 go func() { 50 defer wg.Done() 51 workers := globalExpiryState.workers.Load() 52 for t := range (*workers)[0] { 53 if t, ok := t.(newerNoncurrentTask); ok { 54 expired = append(expired, t.versions...) 55 } 56 } 57 }() 58 lc := lifecycle.Lifecycle{ 59 Rules: []lifecycle.Rule{ 60 { 61 ID: "max-versions", 62 Status: "Enabled", 63 NoncurrentVersionExpiration: lifecycle.NoncurrentVersionExpiration{ 64 NewerNoncurrentVersions: 1, 65 }, 66 }, 67 }, 68 } 69 lcXML, err := xml.Marshal(lc) 70 if err != nil { 71 t.Fatalf("Failed to marshal lifecycle config: %v", err) 72 } 73 vcfg := versioning.Versioning{ 74 Status: "Enabled", 75 } 76 vcfgXML, err := xml.Marshal(vcfg) 77 if err != nil { 78 t.Fatalf("Failed to marshal versioning config: %v", err) 79 } 80 81 bucket := "bucket" 82 obj := "obj-1" 83 now := time.Now() 84 meta := BucketMetadata{ 85 Name: bucket, 86 Created: now, 87 LifecycleConfigXML: lcXML, 88 VersioningConfigXML: vcfgXML, 89 VersioningConfigUpdatedAt: now, 90 LifecycleConfigUpdatedAt: now, 91 lifecycleConfig: &lc, 92 versioningConfig: &vcfg, 93 } 94 globalBucketMetadataSys.Set(bucket, meta) 95 item := scannerItem{ 96 Path: obj, 97 bucket: bucket, 98 prefix: "", 99 objectName: obj, 100 lifeCycle: &lc, 101 } 102 103 modTime := time.Now() 104 uuids := make([]uuid.UUID, 5) 105 for i := range uuids { 106 uuids[i] = uuid.UUID([16]byte{15: uint8(i + 1)}) 107 } 108 fivs := make([]FileInfo, 5) 109 for i := 0; i < 5; i++ { 110 fivs[i] = FileInfo{ 111 Volume: bucket, 112 Name: obj, 113 VersionID: uuids[i].String(), 114 IsLatest: i == 0, 115 ModTime: modTime.Add(-1 * time.Duration(i) * time.Minute), 116 Size: 1 << 10, 117 NumVersions: 5, 118 } 119 } 120 versioned := vcfg.Status == "Enabled" 121 wants := make([]ObjectInfo, 2) 122 for i, fi := range fivs[:2] { 123 wants[i] = fi.ToObjectInfo(bucket, obj, versioned) 124 } 125 gots, err := item.applyNewerNoncurrentVersionLimit(context.TODO(), objAPI, fivs, es) 126 if err != nil { 127 t.Fatalf("Failed with err: %v", err) 128 } 129 if len(gots) != len(wants) { 130 t.Fatalf("Expected %d objects but got %d", len(wants), len(gots)) 131 } 132 133 // Close expiry state's channel to inspect object versions enqueued for expiration 134 close(workers[0]) 135 wg.Wait() 136 for _, obj := range expired { 137 switch obj.ObjectV.VersionID { 138 case uuids[2].String(), uuids[3].String(), uuids[4].String(): 139 default: 140 t.Errorf("Unexpected versionID being expired: %#v\n", obj) 141 } 142 } 143 }