storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/erasure-metadata_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2015, 2016, 2017 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "context" 21 "strconv" 22 "testing" 23 "time" 24 25 humanize "github.com/dustin/go-humanize" 26 ) 27 28 const ActualSize = 1000 29 30 // Test FileInfo.AddObjectPart() 31 func TestAddObjectPart(t *testing.T) { 32 testCases := []struct { 33 partNum int 34 expectedIndex int 35 }{ 36 {1, 0}, 37 {2, 1}, 38 {4, 2}, 39 {5, 3}, 40 {7, 4}, 41 // Insert part. 42 {3, 2}, 43 // Replace existing part. 44 {4, 3}, 45 // Missing part. 46 {6, -1}, 47 } 48 49 // Setup. 50 fi := newFileInfo("test-object", 8, 8) 51 fi.Erasure.Index = 1 52 if !fi.IsValid() { 53 t.Fatalf("unable to get xl meta") 54 } 55 56 // Test them. 57 for _, testCase := range testCases { 58 if testCase.expectedIndex > -1 { 59 partNumString := strconv.Itoa(testCase.partNum) 60 fi.AddObjectPart(testCase.partNum, "etag."+partNumString, int64(testCase.partNum+humanize.MiByte), ActualSize) 61 } 62 63 if index := objectPartIndex(fi.Parts, testCase.partNum); index != testCase.expectedIndex { 64 t.Fatalf("%+v: expected = %d, got: %d", testCase, testCase.expectedIndex, index) 65 } 66 } 67 } 68 69 // Test objectPartIndex(). generates a sample FileInfo data and asserts 70 // the output of objectPartIndex() with the expected value. 71 func TestObjectPartIndex(t *testing.T) { 72 testCases := []struct { 73 partNum int 74 expectedIndex int 75 }{ 76 {2, 1}, 77 {1, 0}, 78 {5, 3}, 79 {4, 2}, 80 {7, 4}, 81 } 82 83 // Setup. 84 fi := newFileInfo("test-object", 8, 8) 85 fi.Erasure.Index = 1 86 if !fi.IsValid() { 87 t.Fatalf("unable to get xl meta") 88 } 89 90 // Add some parts for testing. 91 for _, testCase := range testCases { 92 partNumString := strconv.Itoa(testCase.partNum) 93 fi.AddObjectPart(testCase.partNum, "etag."+partNumString, int64(testCase.partNum+humanize.MiByte), ActualSize) 94 } 95 96 // Add failure test case. 97 testCases = append(testCases, struct { 98 partNum int 99 expectedIndex int 100 }{6, -1}) 101 102 // Test them. 103 for _, testCase := range testCases { 104 if index := objectPartIndex(fi.Parts, testCase.partNum); index != testCase.expectedIndex { 105 t.Fatalf("%+v: expected = %d, got: %d", testCase, testCase.expectedIndex, index) 106 } 107 } 108 } 109 110 // Test FileInfo.ObjectToPartOffset(). 111 func TestObjectToPartOffset(t *testing.T) { 112 // Setup. 113 fi := newFileInfo("test-object", 8, 8) 114 fi.Erasure.Index = 1 115 if !fi.IsValid() { 116 t.Fatalf("unable to get xl meta") 117 } 118 119 // Add some parts for testing. 120 // Total size of all parts is 5,242,899 bytes. 121 for _, partNum := range []int{1, 2, 4, 5, 7} { 122 partNumString := strconv.Itoa(partNum) 123 fi.AddObjectPart(partNum, "etag."+partNumString, int64(partNum+humanize.MiByte), ActualSize) 124 } 125 126 testCases := []struct { 127 offset int64 128 expectedIndex int 129 expectedOffset int64 130 expectedErr error 131 }{ 132 {0, 0, 0, nil}, 133 {1 * humanize.MiByte, 0, 1 * humanize.MiByte, nil}, 134 {1 + humanize.MiByte, 1, 0, nil}, 135 {2 + humanize.MiByte, 1, 1, nil}, 136 // Its valid for zero sized object. 137 {-1, 0, -1, nil}, 138 // Max fffset is always (size - 1). 139 {(1 + 2 + 4 + 5 + 7) + (5 * humanize.MiByte) - 1, 4, 1048582, nil}, 140 // Error if offset is size. 141 {(1 + 2 + 4 + 5 + 7) + (5 * humanize.MiByte), 0, 0, InvalidRange{}}, 142 } 143 144 // Test them. 145 for _, testCase := range testCases { 146 index, offset, err := fi.ObjectToPartOffset(context.Background(), testCase.offset) 147 if err != testCase.expectedErr { 148 t.Fatalf("%+v: expected = %s, got: %s", testCase, testCase.expectedErr, err) 149 } 150 if index != testCase.expectedIndex { 151 t.Fatalf("%+v: index: expected = %d, got: %d", testCase, testCase.expectedIndex, index) 152 } 153 if offset != testCase.expectedOffset { 154 t.Fatalf("%+v: offset: expected = %d, got: %d", testCase, testCase.expectedOffset, offset) 155 } 156 } 157 } 158 159 func TestFindFileInfoInQuorum(t *testing.T) { 160 getNFInfo := func(n int, quorum int, t int64, dataDir string) []FileInfo { 161 fi := newFileInfo("test", 8, 8) 162 fi.AddObjectPart(1, "etag", 100, 100) 163 fi.ModTime = time.Unix(t, 0) 164 fi.DataDir = dataDir 165 fis := make([]FileInfo, n) 166 for i := range fis { 167 fis[i] = fi 168 fis[i].Erasure.Index = i + 1 169 quorum-- 170 if quorum == 0 { 171 break 172 } 173 } 174 return fis 175 } 176 177 tests := []struct { 178 fis []FileInfo 179 modTime time.Time 180 dataDir string 181 expectedErr error 182 }{ 183 { 184 fis: getNFInfo(16, 16, 1603863445, "36a21454-a2ca-11eb-bbaa-93a81c686f21"), 185 modTime: time.Unix(1603863445, 0), 186 dataDir: "36a21454-a2ca-11eb-bbaa-93a81c686f21", 187 expectedErr: nil, 188 }, 189 { 190 fis: getNFInfo(16, 7, 1603863445, "36a21454-a2ca-11eb-bbaa-93a81c686f21"), 191 modTime: time.Unix(1603863445, 0), 192 dataDir: "36a21454-a2ca-11eb-bbaa-93a81c686f21", 193 expectedErr: errErasureReadQuorum, 194 }, 195 } 196 197 for _, test := range tests { 198 test := test 199 t.Run("", func(t *testing.T) { 200 _, err := findFileInfoInQuorum(context.Background(), test.fis, test.modTime, test.dataDir, 8) 201 if err != test.expectedErr { 202 t.Errorf("Expected %s, got %s", test.expectedErr, err) 203 } 204 }) 205 } 206 }