storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/object_api_suite_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 "bytes" 21 "context" 22 "io" 23 "math/rand" 24 "strconv" 25 "testing" 26 27 "github.com/dustin/go-humanize" 28 29 "storj.io/minio/pkg/kms" 30 ) 31 32 // Return pointer to testOneByteReadEOF{} 33 func newTestReaderEOF(data []byte) io.Reader { 34 return &testOneByteReadEOF{false, data} 35 } 36 37 // OneByteReadEOF - implements io.Reader which returns 1 byte along with io.EOF error. 38 type testOneByteReadEOF struct { 39 eof bool 40 data []byte 41 } 42 43 func (r *testOneByteReadEOF) Read(p []byte) (n int, err error) { 44 if r.eof { 45 return 0, io.EOF 46 } 47 n = copy(p, r.data) 48 r.eof = true 49 return n, io.EOF 50 } 51 52 // Return pointer to testOneByteReadNoEOF{} 53 func newTestReaderNoEOF(data []byte) io.Reader { 54 return &testOneByteReadNoEOF{false, data} 55 } 56 57 // testOneByteReadNoEOF - implements io.Reader which returns 1 byte and nil error, but 58 // returns io.EOF on the next Read(). 59 type testOneByteReadNoEOF struct { 60 eof bool 61 data []byte 62 } 63 64 func (r *testOneByteReadNoEOF) Read(p []byte) (n int, err error) { 65 if r.eof { 66 return 0, io.EOF 67 } 68 n = copy(p, r.data) 69 r.eof = true 70 return n, nil 71 } 72 73 // Wrapper for calling testMakeBucket for both Erasure and FS. 74 func TestMakeBucket(t *testing.T) { 75 ExecObjectLayerTest(t, testMakeBucket) 76 } 77 78 // Tests validate bucket creation. 79 func testMakeBucket(obj ObjectLayer, instanceType string, t TestErrHandler) { 80 err := obj.MakeBucketWithLocation(context.Background(), "bucket-unknown", BucketOptions{}) 81 if err != nil { 82 t.Fatalf("%s: <ERROR> %s", instanceType, err) 83 } 84 } 85 86 // Wrapper for calling testMultipartObjectCreation for both Erasure and FS. 87 func TestMultipartObjectCreation(t *testing.T) { 88 ExecExtendedObjectLayerTest(t, testMultipartObjectCreation) 89 } 90 91 // Tests validate creation of part files during Multipart operation. 92 func testMultipartObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) { 93 var opts ObjectOptions 94 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 95 if err != nil { 96 t.Fatalf("%s: <ERROR> %s", instanceType, err) 97 } 98 uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", opts) 99 if err != nil { 100 t.Fatalf("%s: <ERROR> %s", instanceType, err) 101 } 102 // Create a byte array of 5MiB. 103 data := bytes.Repeat([]byte("0123456789abcdef"), 5*humanize.MiByte/16) 104 completedParts := CompleteMultipartUpload{} 105 for i := 1; i <= 10; i++ { 106 expectedETaghex := getMD5Hash(data) 107 108 var calcPartInfo PartInfo 109 calcPartInfo, err = obj.PutObjectPart(context.Background(), "bucket", "key", uploadID, i, mustGetPutObjReader(t, bytes.NewBuffer(data), int64(len(data)), expectedETaghex, ""), opts) 110 if err != nil { 111 t.Errorf("%s: <ERROR> %s", instanceType, err) 112 } 113 if calcPartInfo.ETag != expectedETaghex { 114 t.Errorf("MD5 Mismatch") 115 } 116 completedParts.Parts = append(completedParts.Parts, CompletePart{ 117 PartNumber: i, 118 ETag: calcPartInfo.ETag, 119 }) 120 } 121 objInfo, err := obj.CompleteMultipartUpload(context.Background(), "bucket", "key", uploadID, completedParts.Parts, ObjectOptions{}) 122 if err != nil { 123 t.Fatalf("%s: <ERROR> %s", instanceType, err) 124 } 125 if objInfo.ETag != "7d364cb728ce42a74a96d22949beefb2-10" { 126 t.Errorf("Md5 mismtch") 127 } 128 } 129 130 // Wrapper for calling testMultipartObjectAbort for both Erasure and FS. 131 func TestMultipartObjectAbort(t *testing.T) { 132 ExecObjectLayerTest(t, testMultipartObjectAbort) 133 } 134 135 // Tests validate abortion of Multipart operation. 136 func testMultipartObjectAbort(obj ObjectLayer, instanceType string, t TestErrHandler) { 137 var opts ObjectOptions 138 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 139 if err != nil { 140 t.Fatalf("%s: <ERROR> %s", instanceType, err) 141 } 142 uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", opts) 143 if err != nil { 144 t.Fatalf("%s: <ERROR> %s", instanceType, err) 145 } 146 147 parts := make(map[int]string) 148 metadata := make(map[string]string) 149 for i := 1; i <= 10; i++ { 150 randomPerm := rand.Perm(10) 151 randomString := "" 152 for _, num := range randomPerm { 153 randomString = randomString + strconv.Itoa(num) 154 } 155 156 expectedETaghex := getMD5Hash([]byte(randomString)) 157 158 metadata["md5"] = expectedETaghex 159 var calcPartInfo PartInfo 160 calcPartInfo, err = obj.PutObjectPart(context.Background(), "bucket", "key", uploadID, i, mustGetPutObjReader(t, bytes.NewBufferString(randomString), int64(len(randomString)), expectedETaghex, ""), opts) 161 if err != nil { 162 t.Fatalf("%s: <ERROR> %s", instanceType, err) 163 } 164 if calcPartInfo.ETag != expectedETaghex { 165 t.Errorf("Md5 Mismatch") 166 } 167 parts[i] = expectedETaghex 168 } 169 err = obj.AbortMultipartUpload(context.Background(), "bucket", "key", uploadID, ObjectOptions{}) 170 if err != nil { 171 t.Fatalf("%s: <ERROR> %s", instanceType, err) 172 } 173 } 174 175 // Wrapper for calling testMultipleObjectCreation for both Erasure and FS. 176 func TestMultipleObjectCreation(t *testing.T) { 177 ExecExtendedObjectLayerTest(t, testMultipleObjectCreation) 178 } 179 180 // Tests validate object creation. 181 func testMultipleObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) { 182 objects := make(map[string][]byte) 183 var opts ObjectOptions 184 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 185 if err != nil { 186 t.Fatalf("%s: <ERROR> %s", instanceType, err) 187 } 188 for i := 0; i < 10; i++ { 189 randomPerm := rand.Perm(100) 190 randomString := "" 191 for _, num := range randomPerm { 192 randomString = randomString + strconv.Itoa(num) 193 } 194 195 expectedETaghex := getMD5Hash([]byte(randomString)) 196 197 key := "obj" + strconv.Itoa(i) 198 objects[key] = []byte(randomString) 199 metadata := make(map[string]string) 200 metadata["etag"] = expectedETaghex 201 var objInfo ObjectInfo 202 objInfo, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(randomString), int64(len(randomString)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) 203 if err != nil { 204 t.Fatalf("%s: <ERROR> %s", instanceType, err) 205 } 206 if objInfo.ETag != expectedETaghex { 207 t.Errorf("Md5 Mismatch") 208 } 209 } 210 211 for key, value := range objects { 212 var byteBuffer bytes.Buffer 213 err = GetObject(context.Background(), obj, "bucket", key, 0, int64(len(value)), &byteBuffer, "", opts) 214 if err != nil { 215 t.Fatalf("%s: <ERROR> %s", instanceType, err) 216 } 217 if !bytes.Equal(byteBuffer.Bytes(), value) { 218 t.Errorf("%s: Mismatch of GetObject data with the expected one.", instanceType) 219 } 220 221 objInfo, err := obj.GetObjectInfo(context.Background(), "bucket", key, opts) 222 if err != nil { 223 t.Fatalf("%s: <ERROR> %s", instanceType, err) 224 } 225 if objInfo.Size != int64(len(value)) { 226 t.Errorf("%s: Size mismatch of the GetObject data.", instanceType) 227 } 228 229 } 230 } 231 232 // Wrapper for calling TestPaging for both Erasure and FS. 233 func TestPaging(t *testing.T) { 234 ExecObjectLayerTest(t, testPaging) 235 } 236 237 // Tests validate creation of objects and the order of listing using various filters for ListObjects operation. 238 func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) { 239 obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 240 result, err := obj.ListObjects(context.Background(), "bucket", "", "", "", 0) 241 if err != nil { 242 t.Fatalf("%s: <ERROR> %s", instanceType, err) 243 } 244 if len(result.Objects) != 0 { 245 t.Errorf("%s: Number of objects in the result different from expected value.", instanceType) 246 } 247 if result.IsTruncated { 248 t.Errorf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated) 249 } 250 251 uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." 252 var opts ObjectOptions 253 // check before paging occurs. 254 for i := 0; i < 5; i++ { 255 key := "obj" + strconv.Itoa(i) 256 _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 257 if err != nil { 258 t.Fatalf("%s: <ERROR> %s", instanceType, err) 259 } 260 261 result, err = obj.ListObjects(context.Background(), "bucket", "", "", "", 5) 262 if err != nil { 263 t.Fatalf("%s: <ERROR> %s", instanceType, err) 264 } 265 if len(result.Objects) != i+1 { 266 t.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, len(result.Objects), i+1) 267 } 268 if result.IsTruncated { 269 t.Errorf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated) 270 } 271 } 272 273 // check after paging occurs pages work. 274 for i := 6; i <= 10; i++ { 275 key := "obj" + strconv.Itoa(i) 276 _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 277 if err != nil { 278 t.Fatalf("%s: <ERROR> %s", instanceType, err) 279 } 280 result, err = obj.ListObjects(context.Background(), "bucket", "obj", "", "", 5) 281 if err != nil { 282 t.Fatalf("%s: <ERROR> %s", instanceType, err) 283 } 284 if len(result.Objects) != 5 { 285 t.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, 5, len(result.Objects)) 286 } 287 if !result.IsTruncated { 288 t.Errorf("%s: Expected IsTruncated to be `true`, but instead found it to be `%v`", instanceType, result.IsTruncated) 289 } 290 } 291 // check paging with prefix at end returns less objects. 292 { 293 _, err = obj.PutObject(context.Background(), "bucket", "newPrefix", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 294 if err != nil { 295 t.Fatalf("%s: <ERROR> %s", instanceType, err) 296 } 297 _, err = obj.PutObject(context.Background(), "bucket", "newPrefix2", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 298 if err != nil { 299 t.Fatalf("%s: <ERROR> %s", instanceType, err) 300 } 301 result, err = obj.ListObjects(context.Background(), "bucket", "new", "", "", 5) 302 if err != nil { 303 t.Fatalf("%s: <ERROR> %s", instanceType, err) 304 } 305 if len(result.Objects) != 2 { 306 t.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, 2, len(result.Objects)) 307 } 308 } 309 310 // check ordering of pages. 311 { 312 result, err = obj.ListObjects(context.Background(), "bucket", "", "", "", 1000) 313 if err != nil { 314 t.Fatalf("%s: <ERROR> %s", instanceType, err) 315 } 316 if result.Objects[0].Name != "newPrefix" { 317 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name) 318 } 319 if result.Objects[1].Name != "newPrefix2" { 320 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[1].Name) 321 } 322 if result.Objects[2].Name != "obj0" { 323 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[2].Name) 324 } 325 if result.Objects[3].Name != "obj1" { 326 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[3].Name) 327 } 328 if result.Objects[4].Name != "obj10" { 329 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[4].Name) 330 } 331 } 332 333 // check delimited results with delimiter and prefix. 334 { 335 _, err = obj.PutObject(context.Background(), "bucket", "this/is/delimited", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 336 if err != nil { 337 t.Fatalf("%s: <ERROR> %s", instanceType, err) 338 } 339 _, err = obj.PutObject(context.Background(), "bucket", "this/is/also/a/delimited/file", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 340 if err != nil { 341 t.Fatalf("%s: <ERROR> %s", instanceType, err) 342 } 343 result, err = obj.ListObjects(context.Background(), "bucket", "this/is/", "", SlashSeparator, 10) 344 if err != nil { 345 t.Fatalf("%s: <ERROR> %s", instanceType, err) 346 } 347 if len(result.Objects) != 1 { 348 t.Errorf("%s: Expected the number of objects in the result to be %d, but instead found %d", instanceType, 1, len(result.Objects)) 349 } 350 if result.Prefixes[0] != "this/is/also/" { 351 t.Errorf("%s: Expected prefix to be `%s`, but instead found `%s`", instanceType, "this/is/also/", result.Prefixes[0]) 352 } 353 } 354 355 // check delimited results with delimiter without prefix. 356 { 357 result, err = obj.ListObjects(context.Background(), "bucket", "", "", SlashSeparator, 1000) 358 if err != nil { 359 t.Fatalf("%s: <ERROR> %s", instanceType, err) 360 } 361 362 if result.Objects[0].Name != "newPrefix" { 363 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name) 364 } 365 if result.Objects[1].Name != "newPrefix2" { 366 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[1].Name) 367 } 368 if result.Objects[2].Name != "obj0" { 369 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[2].Name) 370 } 371 if result.Objects[3].Name != "obj1" { 372 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[3].Name) 373 } 374 if result.Objects[4].Name != "obj10" { 375 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[4].Name) 376 } 377 if result.Prefixes[0] != "this/" { 378 t.Errorf("%s: Expected the prefix to be `%s`, but instead found `%s`", instanceType, "this/", result.Prefixes[0]) 379 } 380 } 381 382 // check results with Marker. 383 { 384 385 result, err = obj.ListObjects(context.Background(), "bucket", "", "newPrefix", "", 3) 386 if err != nil { 387 t.Fatalf("%s: <ERROR> %s", instanceType, err) 388 } 389 if result.Objects[0].Name != "newPrefix2" { 390 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix2", result.Objects[0].Name) 391 } 392 if result.Objects[1].Name != "obj0" { 393 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj0", result.Objects[1].Name) 394 } 395 if result.Objects[2].Name != "obj1" { 396 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj1", result.Objects[2].Name) 397 } 398 } 399 // check ordering of results with prefix. 400 { 401 result, err = obj.ListObjects(context.Background(), "bucket", "obj", "", "", 1000) 402 if err != nil { 403 t.Fatalf("%s: <ERROR> %s", instanceType, err) 404 } 405 if result.Objects[0].Name != "obj0" { 406 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj0", result.Objects[0].Name) 407 } 408 if result.Objects[1].Name != "obj1" { 409 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj1", result.Objects[1].Name) 410 } 411 if result.Objects[2].Name != "obj10" { 412 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj10", result.Objects[2].Name) 413 } 414 if result.Objects[3].Name != "obj2" { 415 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj2", result.Objects[3].Name) 416 } 417 if result.Objects[4].Name != "obj3" { 418 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj3", result.Objects[4].Name) 419 } 420 } 421 // check ordering of results with prefix and no paging. 422 { 423 result, err = obj.ListObjects(context.Background(), "bucket", "new", "", "", 5) 424 if err != nil { 425 t.Fatalf("%s: <ERROR> %s", instanceType, err) 426 } 427 if result.Objects[0].Name != "newPrefix" { 428 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name) 429 } 430 if result.Objects[1].Name != "newPrefix2" { 431 t.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix2", result.Objects[0].Name) 432 } 433 } 434 } 435 436 // Wrapper for calling testObjectOverwriteWorks for both Erasure and FS. 437 func TestObjectOverwriteWorks(t *testing.T) { 438 ExecObjectLayerTest(t, testObjectOverwriteWorks) 439 } 440 441 // Tests validate overwriting of an existing object. 442 func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, t TestErrHandler) { 443 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 444 if err != nil { 445 t.Fatalf("%s: <ERROR> %s", instanceType, err) 446 } 447 448 var opts ObjectOptions 449 uploadContent := "The list of parts was not in ascending order. The parts list must be specified in order by part number." 450 length := int64(len(uploadContent)) 451 _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) 452 if err != nil { 453 t.Fatalf("%s: <ERROR> %s", instanceType, err) 454 } 455 456 uploadContent = "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." 457 length = int64(len(uploadContent)) 458 _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) 459 if err != nil { 460 t.Fatalf("%s: <ERROR> %s", instanceType, err) 461 } 462 463 var bytesBuffer bytes.Buffer 464 err = GetObject(context.Background(), obj, "bucket", "object", 0, length, &bytesBuffer, "", opts) 465 if err != nil { 466 t.Fatalf("%s: <ERROR> %s", instanceType, err) 467 } 468 if bytesBuffer.String() != "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." { 469 t.Errorf("%s: Invalid upload ID error mismatch.", instanceType) 470 } 471 } 472 473 // Wrapper for calling testNonExistantBucketOperations for both Erasure and FS. 474 func TestNonExistantBucketOperations(t *testing.T) { 475 ExecObjectLayerTest(t, testNonExistantBucketOperations) 476 } 477 478 // Tests validate that bucket operation on non-existent bucket fails. 479 func testNonExistantBucketOperations(obj ObjectLayer, instanceType string, t TestErrHandler) { 480 var opts ObjectOptions 481 _, err := obj.PutObject(context.Background(), "bucket1", "object", mustGetPutObjReader(t, bytes.NewBufferString("one"), int64(len("one")), "", ""), opts) 482 if err == nil { 483 t.Fatal("Expected error but found nil") 484 } 485 if err.Error() != "Bucket not found: bucket1" { 486 t.Errorf("%s: Expected the error msg to be `%s`, but instead found `%s`", instanceType, "Bucket not found: bucket1", err.Error()) 487 } 488 } 489 490 // Wrapper for calling testBucketRecreateFails for both Erasure and FS. 491 func TestBucketRecreateFails(t *testing.T) { 492 ExecObjectLayerTest(t, testBucketRecreateFails) 493 } 494 495 // Tests validate that recreation of the bucket fails. 496 func testBucketRecreateFails(obj ObjectLayer, instanceType string, t TestErrHandler) { 497 err := obj.MakeBucketWithLocation(context.Background(), "string", BucketOptions{}) 498 if err != nil { 499 t.Fatalf("%s: <ERROR> %s", instanceType, err) 500 } 501 err = obj.MakeBucketWithLocation(context.Background(), "string", BucketOptions{}) 502 if err == nil { 503 t.Fatalf("%s: Expected error but found nil.", instanceType) 504 } 505 506 if err.Error() != "Bucket exists: string" { 507 t.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, "Bucket exists: string", err.Error()) 508 } 509 } 510 511 func enableCompression(t *testing.T, encrypt bool) { 512 // Enable compression and exec... 513 globalCompressConfigMu.Lock() 514 globalCompressConfig.Enabled = true 515 globalCompressConfig.MimeTypes = nil 516 globalCompressConfig.Extensions = nil 517 globalCompressConfig.AllowEncrypted = encrypt 518 globalCompressConfigMu.Unlock() 519 if encrypt { 520 globalAutoEncryption = encrypt 521 var err error 522 GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=") 523 if err != nil { 524 t.Fatal(err) 525 } 526 } 527 } 528 529 func enableEncrytion(t *testing.T) { 530 // Exec with default settings... 531 globalCompressConfigMu.Lock() 532 globalCompressConfig.Enabled = false 533 globalCompressConfigMu.Unlock() 534 535 globalAutoEncryption = true 536 var err error 537 GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=") 538 if err != nil { 539 t.Fatal(err) 540 } 541 } 542 543 func resetCompressEncryption() { 544 // Reset... 545 globalCompressConfigMu.Lock() 546 globalCompressConfig.Enabled = false 547 globalCompressConfig.AllowEncrypted = false 548 globalCompressConfigMu.Unlock() 549 globalAutoEncryption = false 550 GlobalKMS = nil 551 } 552 553 func execExtended(t *testing.T, fn func(t *testing.T)) { 554 // Exec with default settings... 555 resetCompressEncryption() 556 t.Run("default", func(t *testing.T) { 557 fn(t) 558 }) 559 560 if testing.Short() { 561 return 562 } 563 564 t.Run("compressed", func(t *testing.T) { 565 resetCompressEncryption() 566 enableCompression(t, false) 567 fn(t) 568 }) 569 570 t.Run("encrypted", func(t *testing.T) { 571 resetCompressEncryption() 572 enableEncrytion(t) 573 fn(t) 574 }) 575 576 t.Run("compressed+encrypted", func(t *testing.T) { 577 resetCompressEncryption() 578 enableCompression(t, true) 579 fn(t) 580 }) 581 } 582 583 // ExecExtendedObjectLayerTest will execute the tests with combinations of encrypted & compressed. 584 // This can be used to test functionality when reading and writing data. 585 func ExecExtendedObjectLayerTest(t *testing.T, objTest objTestType) { 586 execExtended(t, func(t *testing.T) { 587 ExecObjectLayerTest(t, objTest) 588 }) 589 } 590 591 // Wrapper for calling testPutObject for both Erasure and FS. 592 func TestPutObject(t *testing.T) { 593 ExecExtendedObjectLayerTest(t, testPutObject) 594 } 595 596 // Tests validate PutObject without prefix. 597 func testPutObject(obj ObjectLayer, instanceType string, t TestErrHandler) { 598 content := []byte("testcontent") 599 length := int64(len(content)) 600 readerEOF := newTestReaderEOF(content) 601 readerNoEOF := newTestReaderNoEOF(content) 602 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 603 if err != nil { 604 t.Fatalf("%s: <ERROR> %s", instanceType, err) 605 } 606 607 var bytesBuffer1 bytes.Buffer 608 var opts ObjectOptions 609 _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerEOF, length, "", ""), opts) 610 if err != nil { 611 t.Fatalf("%s: <ERROR> %s", instanceType, err) 612 } 613 err = GetObject(context.Background(), obj, "bucket", "object", 0, length, &bytesBuffer1, "", opts) 614 if err != nil { 615 t.Fatalf("%s: <ERROR> %s", instanceType, err) 616 } 617 if len(bytesBuffer1.Bytes()) != len(content) { 618 t.Errorf("%s: Expected content length to be `%d`, but instead found `%d`", instanceType, len(content), len(bytesBuffer1.Bytes())) 619 } 620 621 var bytesBuffer2 bytes.Buffer 622 _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerNoEOF, length, "", ""), opts) 623 if err != nil { 624 t.Fatalf("%s: <ERROR> %s", instanceType, err) 625 } 626 err = GetObject(context.Background(), obj, "bucket", "object", 0, length, &bytesBuffer2, "", opts) 627 if err != nil { 628 t.Fatalf("%s: <ERROR> %s", instanceType, err) 629 } 630 if len(bytesBuffer2.Bytes()) != len(content) { 631 t.Errorf("%s: Expected content length to be `%d`, but instead found `%d`", instanceType, len(content), len(bytesBuffer2.Bytes())) 632 } 633 } 634 635 // Wrapper for calling testPutObjectInSubdir for both Erasure and FS. 636 func TestPutObjectInSubdir(t *testing.T) { 637 ExecExtendedObjectLayerTest(t, testPutObjectInSubdir) 638 } 639 640 // Tests validate PutObject with subdirectory prefix. 641 func testPutObjectInSubdir(obj ObjectLayer, instanceType string, t TestErrHandler) { 642 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 643 if err != nil { 644 t.Fatalf("%s: <ERROR> %s", instanceType, err) 645 } 646 647 var opts ObjectOptions 648 uploadContent := `The specified multipart upload does not exist. The upload ID might be invalid, or the multipart 649 upload might have been aborted or completed.` 650 length := int64(len(uploadContent)) 651 _, err = obj.PutObject(context.Background(), "bucket", "dir1/dir2/object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) 652 if err != nil { 653 t.Fatalf("%s: <ERROR> %s", instanceType, err) 654 } 655 656 var bytesBuffer bytes.Buffer 657 err = GetObject(context.Background(), obj, "bucket", "dir1/dir2/object", 0, length, &bytesBuffer, "", opts) 658 if err != nil { 659 t.Fatalf("%s: <ERROR> %s", instanceType, err) 660 } 661 if len(bytesBuffer.Bytes()) != len(uploadContent) { 662 t.Errorf("%s: Expected length of downloaded data to be `%d`, but instead found `%d`", 663 instanceType, len(uploadContent), len(bytesBuffer.Bytes())) 664 } 665 } 666 667 // Wrapper for calling testListBuckets for both Erasure and FS. 668 func TestListBuckets(t *testing.T) { 669 ExecObjectLayerTest(t, testListBuckets) 670 } 671 672 // Tests validate ListBuckets. 673 func testListBuckets(obj ObjectLayer, instanceType string, t TestErrHandler) { 674 // test empty list. 675 buckets, err := obj.ListBuckets(context.Background()) 676 if err != nil { 677 t.Fatalf("%s: <ERROR> %s", instanceType, err) 678 } 679 if len(buckets) != 0 { 680 t.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 0, len(buckets)) 681 } 682 683 // add one and test exists. 684 err = obj.MakeBucketWithLocation(context.Background(), "bucket1", BucketOptions{}) 685 if err != nil { 686 t.Fatalf("%s: <ERROR> %s", instanceType, err) 687 } 688 689 buckets, err = obj.ListBuckets(context.Background()) 690 if err != nil { 691 t.Fatalf("%s: <ERROR> %s", instanceType, err) 692 } 693 if len(buckets) != 1 { 694 t.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 1, len(buckets)) 695 } 696 697 // add two and test exists. 698 err = obj.MakeBucketWithLocation(context.Background(), "bucket2", BucketOptions{}) 699 if err != nil { 700 t.Fatalf("%s: <ERROR> %s", instanceType, err) 701 } 702 703 buckets, err = obj.ListBuckets(context.Background()) 704 if err != nil { 705 t.Fatalf("%s: <ERROR> %s", instanceType, err) 706 } 707 if len(buckets) != 2 { 708 t.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 2, len(buckets)) 709 } 710 711 // add three and test exists + prefix. 712 err = obj.MakeBucketWithLocation(context.Background(), "bucket22", BucketOptions{}) 713 if err != nil { 714 t.Fatalf("%s: <ERROR> %s", instanceType, err) 715 } 716 717 buckets, err = obj.ListBuckets(context.Background()) 718 if err != nil { 719 t.Fatalf("%s: <ERROR> %s", instanceType, err) 720 } 721 if len(buckets) != 3 { 722 t.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 3, len(buckets)) 723 } 724 } 725 726 // Wrapper for calling testListBucketsOrder for both Erasure and FS. 727 func TestListBucketsOrder(t *testing.T) { 728 ExecObjectLayerTest(t, testListBucketsOrder) 729 } 730 731 // Tests validate the order of result of ListBuckets. 732 func testListBucketsOrder(obj ObjectLayer, instanceType string, t TestErrHandler) { 733 // if implementation contains a map, order of map keys will vary. 734 // this ensures they return in the same order each time. 735 // add one and test exists. 736 err := obj.MakeBucketWithLocation(context.Background(), "bucket1", BucketOptions{}) 737 if err != nil { 738 t.Fatalf("%s: <ERROR> %s", instanceType, err) 739 } 740 err = obj.MakeBucketWithLocation(context.Background(), "bucket2", BucketOptions{}) 741 if err != nil { 742 t.Fatalf("%s: <ERROR> %s", instanceType, err) 743 } 744 buckets, err := obj.ListBuckets(context.Background()) 745 if err != nil { 746 t.Fatalf("%s: <ERROR> %s", instanceType, err) 747 } 748 if len(buckets) != 2 { 749 t.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 2, len(buckets)) 750 } 751 752 if buckets[0].Name != "bucket1" { 753 t.Errorf("%s: Expected bucket name to be `%s`, but instead found `%s`", instanceType, "bucket1", buckets[0].Name) 754 } 755 if buckets[1].Name != "bucket2" { 756 t.Errorf("%s: Expected bucket name to be `%s`, but instead found `%s`", instanceType, "bucket2", buckets[1].Name) 757 } 758 } 759 760 // Wrapper for calling testListObjectsTestsForNonExistantBucket for both Erasure and FS. 761 func TestListObjectsTestsForNonExistantBucket(t *testing.T) { 762 ExecObjectLayerTest(t, testListObjectsTestsForNonExistantBucket) 763 } 764 765 // Tests validate that ListObjects operation on a non-existent bucket fails as expected. 766 func testListObjectsTestsForNonExistantBucket(obj ObjectLayer, instanceType string, t TestErrHandler) { 767 result, err := obj.ListObjects(context.Background(), "bucket", "", "", "", 1000) 768 if err == nil { 769 t.Fatalf("%s: Expected error but found nil.", instanceType) 770 } 771 if len(result.Objects) != 0 { 772 t.Fatalf("%s: Expected number of objects in the result to be `%d`, but instead found `%d`", instanceType, 0, len(result.Objects)) 773 } 774 if result.IsTruncated { 775 t.Fatalf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated) 776 } 777 if err.Error() != "Bucket not found: bucket" { 778 t.Errorf("%s: Expected the error msg to be `%s`, but instead found `%s`", instanceType, "Bucket not found: bucket", err.Error()) 779 } 780 } 781 782 // Wrapper for calling testNonExistantObjectInBucket for both Erasure and FS. 783 func TestNonExistantObjectInBucket(t *testing.T) { 784 ExecObjectLayerTest(t, testNonExistantObjectInBucket) 785 } 786 787 // Tests validate that GetObject fails on a non-existent bucket as expected. 788 func testNonExistantObjectInBucket(obj ObjectLayer, instanceType string, t TestErrHandler) { 789 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 790 if err != nil { 791 t.Fatalf("%s: <ERROR> %s", instanceType, err) 792 } 793 794 _, err = obj.GetObjectInfo(context.Background(), "bucket", "dir1", ObjectOptions{}) 795 if err == nil { 796 t.Fatalf("%s: Expected error but found nil", instanceType) 797 } 798 if isErrObjectNotFound(err) { 799 if err.Error() != "Object not found: bucket/dir1" { 800 t.Errorf("%s: Expected the Error message to be `%s`, but instead found `%s`", instanceType, "Object not found: bucket/dir1", err.Error()) 801 } 802 } else { 803 if err.Error() != "fails" { 804 t.Errorf("%s: Expected the Error message to be `%s`, but instead found it to be `%s`", instanceType, "fails", err.Error()) 805 } 806 } 807 } 808 809 // Wrapper for calling testGetDirectoryReturnsObjectNotFound for both Erasure and FS. 810 func TestGetDirectoryReturnsObjectNotFound(t *testing.T) { 811 ExecObjectLayerTest(t, testGetDirectoryReturnsObjectNotFound) 812 } 813 814 // Tests validate that GetObject on an existing directory fails as expected. 815 func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, t TestErrHandler) { 816 bucketName := "bucket" 817 err := obj.MakeBucketWithLocation(context.Background(), bucketName, BucketOptions{}) 818 if err != nil { 819 t.Fatalf("%s: <ERROR> %s", instanceType, err) 820 } 821 content := "One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag." 822 length := int64(len(content)) 823 var opts ObjectOptions 824 _, err = obj.PutObject(context.Background(), bucketName, "dir1/dir3/object", mustGetPutObjReader(t, bytes.NewBufferString(content), length, "", ""), opts) 825 826 if err != nil { 827 t.Fatalf("%s: <ERROR> %s", instanceType, err) 828 } 829 830 testCases := []struct { 831 dir string 832 err error 833 }{ 834 { 835 dir: "dir1/", 836 err: ObjectNotFound{Bucket: bucketName, Object: "dir1/"}, 837 }, 838 { 839 dir: "dir1/dir3/", 840 err: ObjectNotFound{Bucket: bucketName, Object: "dir1/dir3/"}, 841 }, 842 } 843 844 for i, testCase := range testCases { 845 _, expectedErr := obj.GetObjectInfo(context.Background(), bucketName, testCase.dir, opts) 846 if expectedErr != nil && expectedErr.Error() != testCase.err.Error() { 847 t.Errorf("Test %d, %s: Expected error %s, got %s", i+1, instanceType, testCase.err, expectedErr) 848 } 849 } 850 } 851 852 // Wrapper for calling testContentType for both Erasure and FS. 853 func TestContentType(t *testing.T) { 854 ExecObjectLayerTest(t, testContentType) 855 } 856 857 // Test content-type. 858 func testContentType(obj ObjectLayer, instanceType string, t TestErrHandler) { 859 err := obj.MakeBucketWithLocation(context.Background(), "bucket", BucketOptions{}) 860 if err != nil { 861 t.Fatalf("%s: <ERROR> %s", instanceType, err) 862 } 863 var opts ObjectOptions 864 uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." 865 // Test empty. 866 _, err = obj.PutObject(context.Background(), "bucket", "minio.png", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) 867 if err != nil { 868 t.Fatalf("%s: <ERROR> %s", instanceType, err) 869 } 870 objInfo, err := obj.GetObjectInfo(context.Background(), "bucket", "minio.png", opts) 871 if err != nil { 872 t.Fatalf("%s: <ERROR> %s", instanceType, err) 873 } 874 875 if objInfo.ContentType != "image/png" { 876 t.Errorf("%s: Expected Content type to be `%s`, but instead found `%s`", instanceType, "image/png", objInfo.ContentType) 877 } 878 }