From 1f51af6f37375bb1965bd56bf4051e999a6987fd Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Tue, 24 May 2016 15:05:55 +0530 Subject: [PATCH] Listmultipart tests. --- object-api-multipart_test.go | 900 +++++++++++++++++++++++++++++++++++ 1 file changed, 900 insertions(+) diff --git a/object-api-multipart_test.go b/object-api-multipart_test.go index 91e4f6a3b..aaa785db7 100644 --- a/object-api-multipart_test.go +++ b/object-api-multipart_test.go @@ -19,6 +19,7 @@ package main import ( "bytes" "fmt" + "strings" "testing" ) @@ -219,3 +220,902 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t *testing } } } + +// Wrapper for calling TestListMultipartUploads tests for both XL multiple disks and single node setup. +func TestListMultipartUploads(t *testing.T) { + ExecObjectLayerTest(t, testListMultipartUploads) +} + +// testListMultipartUploads - Tests validate listing of multipart uploads. +func testListMultipartUploads(obj ObjectLayer, instanceType string, t *testing.T) { + + bucketNames := []string{"minio-bucket", "minio-2-bucket", "minio-3-bucket"} + objectNames := []string{"minio-object-1.txt", "minio-object.txt", "neymar-1.jpeg", "neymar.jpeg", "parrot-1.png", "parrot.png"} + uploadIDs := []string{} + + // bucketnames[0]. + // objectNames[0]. + // uploadIds [0]. + // Create bucket before intiating NewMultipartUpload. + err := obj.MakeBucket(bucketNames[0]) + if err != nil { + // Failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + // Initiate Multipart Upload on the above created bucket. + uploadID, err := obj.NewMultipartUpload(bucketNames[0], objectNames[0], nil) + if err != nil { + // Failed to create NewMultipartUpload, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + + uploadIDs = append(uploadIDs, uploadID) + + // bucketnames[1]. + // objectNames[0]. + // uploadIds [1-3]. + // Bucket to test for mutiple upload Id's for a given object. + err = obj.MakeBucket(bucketNames[1]) + if err != nil { + // Failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + for i := 0; i < 3; i++ { + // Initiate Multipart Upload on bucketNames[1] for the same object 3 times. + // Used to test the listing for the case of multiple uploadID's for a given object. + uploadID, err = obj.NewMultipartUpload(bucketNames[1], objectNames[0], nil) + if err != nil { + // Failed to create NewMultipartUpload, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + + uploadIDs = append(uploadIDs, uploadID) + } + + // Bucket to test for mutiple objects, each with unique UUID. + // bucketnames[2]. + // objectNames[0-2]. + // uploadIds [4-9]. + err = obj.MakeBucket(bucketNames[2]) + if err != nil { + // Failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + // Initiate Multipart Upload on bucketNames[2]. + // Used to test the listing for the case of multiple objects for a given bucket. + for i := 0; i < 6; i++ { + uploadID, err := obj.NewMultipartUpload(bucketNames[2], objectNames[i], nil) + if err != nil { + // Failed to create NewMultipartUpload, abort. + t.Fatalf("%s : %s", instanceType, err.Error()) + } + // uploadIds [4-9]. + uploadIDs = append(uploadIDs, uploadID) + } + // Create multipart parts. + // Need parts to be uploaded before MultipartLists can be called and tested. + createPartCases := []struct { + bucketName string + objName string + uploadID string + PartID int + inputReaderData string + inputMd5 string + intputDataSize int64 + expectedMd5 string + }{ + // Case 1-4. + // Creating sequence of parts for same uploadID. + // Used to ensure that the ListMultipartResult produces one output for the four parts uploaded below for the given upload ID. + {bucketNames[0], objectNames[0], uploadIDs[0], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[0], objectNames[0], uploadIDs[0], 2, "efgh", "1f7690ebdd9b4caf8fab49ca1757bf27", int64(len("efgh")), "1f7690ebdd9b4caf8fab49ca1757bf27"}, + {bucketNames[0], objectNames[0], uploadIDs[0], 3, "ijkl", "09a0877d04abf8759f99adec02baf579", int64(len("abcd")), "09a0877d04abf8759f99adec02baf579"}, + {bucketNames[0], objectNames[0], uploadIDs[0], 4, "mnop", "e132e96a5ddad6da8b07bba6f6131fef", int64(len("abcd")), "e132e96a5ddad6da8b07bba6f6131fef"}, + // Cases 5-7. + // Create parts with 3 uploadID's for the same object. + // Testing for listing of all the uploadID's for given object. + // Insertion with 3 different uploadID's are done for same bucket and object. + {bucketNames[1], objectNames[0], uploadIDs[1], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[1], objectNames[0], uploadIDs[2], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[1], objectNames[0], uploadIDs[3], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + // Case 8-13. + // Generating parts for different objects. + {bucketNames[2], objectNames[0], uploadIDs[4], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[2], objectNames[1], uploadIDs[5], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[2], objectNames[2], uploadIDs[6], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[2], objectNames[3], uploadIDs[7], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[2], objectNames[4], uploadIDs[8], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + {bucketNames[2], objectNames[5], uploadIDs[9], 1, "abcd", "e2fc714c4727ee9395f324cd2e7f331f", int64(len("abcd")), "e2fc714c4727ee9395f324cd2e7f331f"}, + } + // Iterating over creatPartCases to generate multipart chunks. + for _, testCase := range createPartCases { + _, err := obj.PutObjectPart(testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, testCase.intputDataSize, + bytes.NewBufferString(testCase.inputReaderData), testCase.inputMd5) + if err != nil { + t.Fatalf("%s : %s", instanceType, err.Error()) + } + + } + + // Expected Results set for asserting ListObjectMultipart test. + listMultipartResults := []ListMultipartsInfo{ + // listMultipartResults - 1. + // Used to check that the result produces only one output for the 4 parts uploaded in cases 1-4 of createPartCases above. + // ListMultipartUploads doesn't list the parts. + { + MaxUploads: 100, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 2. + // Used to check that the result produces only one output for the 4 parts uploaded in cases 1-4 of createPartCases above. + // `KeyMarker` is set. + // ListMultipartUploads doesn't list the parts. + { + MaxUploads: 100, + KeyMarker: "kin", + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 3. + // `KeyMarker` is set, no uploadMetadata expected. + // ListMultipartUploads doesn't list the parts. + // `Maxupload` value is asserted. + { + MaxUploads: 100, + KeyMarker: "orange", + }, + // listMultipartResults - 4. + // `KeyMarker` is set, no uploadMetadata expected. + // Maxupload value is asserted. + { + MaxUploads: 1, + KeyMarker: "orange", + }, + // listMultipartResults - 5. + // `KeyMarker` is set. It contains part of the objectname as `KeyPrefix`. + // Expecting the result to contain one uploadMetadata entry and Istruncated to be false. + { + MaxUploads: 10, + KeyMarker: "min", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 6. + // `KeyMarker` is set. It contains part of the objectname as `KeyPrefix`. + // `MaxUploads` is set equal to the number of meta data entries in the result, the result contains only one entry. + // Expecting the result to contain one uploadMetadata entry and IsTruncated to be false. + { + MaxUploads: 1, + KeyMarker: "min", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 7. + // `KeyMarker` is set. It contains part of the objectname as `KeyPrefix`. + // Testing for the case with `MaxUploads` set to 0. + // Expecting the result to contain no uploadMetadata entry since `MaxUploads` is set to 0. + // Expecting `IsTruncated` to be true. + { + MaxUploads: 0, + KeyMarker: "min", + IsTruncated: true, + }, + // listMultipartResults - 8. + // `KeyMarker` is set. It contains part of the objectname as KeyPrefix. + // Testing for the case with `MaxUploads` set to 0. + // Expecting the result to contain no uploadMetadata entry since `MaxUploads` is set to 0. + // Expecting `isTruncated` to be true. + { + MaxUploads: 0, + KeyMarker: "min", + IsTruncated: true, + }, + // listMultipartResults - 9. + // `KeyMarker` is set. It contains part of the objectname as KeyPrefix. + // `KeyMarker` is set equal to the object name in the result. + // Expecting the result to skip the `KeyMarker` entry. + { + MaxUploads: 2, + KeyMarker: "minio-object", + IsTruncated: false, + }, + // listMultipartResults - 10. + // Prefix is set. It is set equal to the object name. + // MaxUploads is set more than number of meta data entries in the result. + // Expecting the result to contain one uploadMetadata entry and IsTruncated to be false. + { + MaxUploads: 2, + Prefix: "minio-object", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 11. + // Setting `Prefix` to contain the object name as its prefix. + // MaxUploads is set more than number of meta data entries in the result. + // Expecting the result to contain one uploadMetadata entry and IsTruncated to be false. + { + MaxUploads: 2, + Prefix: "min", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 12. + // Setting `Prefix` to contain the object name as its prefix. + // MaxUploads is set equal to number of meta data entries in the result. + // Expecting the result to contain one uploadMetadata entry and IsTruncated to be false. + { + MaxUploads: 1, + Prefix: "min", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 13. + // `Prefix` is set. It doesn't contain object name as its preifx. + // MaxUploads is set more than number of meta data entries in the result. + // Expecting no `Uploads` metadata. + { + MaxUploads: 2, + Prefix: "orange", + IsTruncated: false, + }, + // listMultipartResults - 14. + // `Prefix` is set. It doesn't contain object name as its preifx. + // MaxUploads is set more than number of meta data entries in the result. + // Expecting no `Uploads` metadata. + { + MaxUploads: 2, + Prefix: "Asia", + IsTruncated: false, + }, + // listMultipartResults - 15. + // Setting `Delimiter`. + // MaxUploads is set more than number of meta data entries in the result. + // Expecting the result to contain one uploadMetadata entry and IsTruncated to be false. + { + MaxUploads: 2, + Delimiter: "/", + Prefix: "", + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[0], + }, + }, + }, + // listMultipartResults - 16. + // Testing for listing of 3 uploadID's for a given object. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 100, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[1], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + // listMultipartResults - 17. + // Testing for listing of 3 uploadID's (uploadIDs[1-3]) for a given object with uploadID Marker set. + // uploadIDs[1] is set as UploadMarker, Expecting it to be skipped in the result. + // uploadIDs[2] and uploadIDs[3] are expected to be in the result. + // Istruncted is expected to be false. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 100, + UploadIDMarker: uploadIDs[1], + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + // listMultipartResults - 18. + // Testing for listing of 3 uploadID's (uploadIDs[1-3]) for a given object with uploadID Marker set. + // uploadIDs[2] is set as UploadMarker, Expecting it to be skipped in the result. + // Only uploadIDs[3] are expected to be in the result. + // Istruncted is expected to be false. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 100, + UploadIDMarker: uploadIDs[2], + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + // listMultipartResults - 19. + // Testing for listing of 3 uploadID's for a given object, setting maxKeys to be 2. + // There are 3 uploadMetadata in the result (uploadIDs[1-3]), it should be truncated to 2. + // Since there is only single object for bucketNames[1], the NextKeyMarker is set to its name. + // The last entry in the result, uploadIDs[2], that is should be set as NextUploadIDMarker. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 2, + IsTruncated: true, + NextKeyMarker: objectNames[0], + NextUploadIDMarker: uploadIDs[2], + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[1], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + }, + }, + // listMultipartResults - 20. + // Testing for listing of 3 uploadID's for a given object, setting maxKeys to be 1. + // There are 3 uploadMetadata in the result (uploadIDs[1-3]), it should be truncated to 1. + // The last entry in the result, uploadIDs[1], that is should be set as NextUploadIDMarker. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 1, + IsTruncated: true, + NextKeyMarker: objectNames[0], + NextUploadIDMarker: uploadIDs[1], + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[1], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + }, + }, + // listMultipartResults - 21. + // Testing for listing of 3 uploadID's for a given object, setting maxKeys to be 3. + // There are 3 uploadMetadata in the result (uploadIDs[1-3]), hence no truncation is expected. + // Since all the uploadMetadata is listed, expecting no values for NextUploadIDMarker and NextKeyMarker. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 3, + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[1], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + // listMultipartResults - 22. + // Testing for listing of 3 uploadID's for a given object, setting `prefix` to be "min". + // Will be used to list on bucketNames[1]. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "min", + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[1], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + // listMultipartResults - 23. + // Testing for listing of 3 uploadID's for a given object + // setting `prefix` to be "orange". + // Will be used to list on bucketNames[1]. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "orange", + }, + // listMultipartResults - 24. + // Testing for listing of 3 uploadID's for a given object. + // setting `prefix` to be "Asia". + // Will be used to list on bucketNames[1]. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "Asia", + }, + // listMultipartResults - 25. + // Testing for listing of 3 uploadID's for a given object. + // setting `prefix` and uploadIDMarker. + // Will be used to list on bucketNames[1]. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "minio", + UploadIDMarker: uploadIDs[0], + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[2], + }, + { + Object: objectNames[0], + UploadID: uploadIDs[3], + }, + }, + }, + + // Operations on bucket 2. + // listMultipartResults - 26. + // checking listing everything. + { + MaxUploads: 100, + IsTruncated: false, + + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[4], + }, + { + Object: objectNames[1], + UploadID: uploadIDs[5], + }, + { + Object: objectNames[2], + UploadID: uploadIDs[6], + }, + { + Object: objectNames[3], + UploadID: uploadIDs[7], + }, + { + Object: objectNames[4], + UploadID: uploadIDs[8], + }, + { + Object: objectNames[5], + UploadID: uploadIDs[9], + }, + }, + }, + // listMultipartResults - 27. + // listing with `prefix` "min". + { + MaxUploads: 100, + IsTruncated: false, + Prefix: "min", + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[4], + }, + { + Object: objectNames[1], + UploadID: uploadIDs[5], + }, + }, + }, + // listMultipartResults - 28. + // listing with `prefix` "ney". + { + MaxUploads: 100, + IsTruncated: false, + Prefix: "ney", + Uploads: []uploadMetadata{ + { + Object: objectNames[2], + UploadID: uploadIDs[6], + }, + { + Object: objectNames[3], + UploadID: uploadIDs[7], + }, + }, + }, + // listMultipartResults - 29. + // listing with `prefix` "parrot". + { + MaxUploads: 100, + IsTruncated: false, + Prefix: "parrot", + Uploads: []uploadMetadata{ + { + Object: objectNames[4], + UploadID: uploadIDs[8], + }, + { + Object: objectNames[5], + UploadID: uploadIDs[9], + }, + }, + }, + // listMultipartResults - 30. + // listing with `prefix` "neymar.jpeg". + // prefix set to object name. + { + MaxUploads: 100, + IsTruncated: false, + Prefix: "neymar.jpeg", + Uploads: []uploadMetadata{ + { + Object: objectNames[3], + UploadID: uploadIDs[7], + }, + }, + }, + + // listMultipartResults - 31. + // checking listing with marker set to 3. + // `NextUploadIDMarker` is expected to be set on last uploadID in the result. + // `NextKeyMarker` is expected to be set on the last object key in the list. + { + MaxUploads: 3, + IsTruncated: true, + NextUploadIDMarker: uploadIDs[6], + NextKeyMarker: objectNames[2], + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[4], + }, + { + Object: objectNames[1], + UploadID: uploadIDs[5], + }, + { + Object: objectNames[2], + UploadID: uploadIDs[6], + }, + }, + }, + // listMultipartResults - 32. + // checking listing with marker set to no of objects in the list. + // `NextUploadIDMarker` is expected to be empty since all results are listed. + // `NextKeyMarker` is expected to be empty since all results are listed. + { + MaxUploads: 6, + IsTruncated: false, + Uploads: []uploadMetadata{ + { + Object: objectNames[0], + UploadID: uploadIDs[4], + }, + { + Object: objectNames[1], + UploadID: uploadIDs[5], + }, + { + Object: objectNames[2], + UploadID: uploadIDs[6], + }, + { + Object: objectNames[3], + UploadID: uploadIDs[7], + }, + { + Object: objectNames[4], + UploadID: uploadIDs[8], + }, + { + Object: objectNames[5], + UploadID: uploadIDs[9], + }, + }, + }, + // listMultipartResults - 33. + // checking listing with `UploadIDMarker` set. + { + MaxUploads: 10, + IsTruncated: false, + UploadIDMarker: uploadIDs[6], + Uploads: []uploadMetadata{ + { + Object: objectNames[3], + UploadID: uploadIDs[7], + }, + { + Object: objectNames[4], + UploadID: uploadIDs[8], + }, + { + Object: objectNames[5], + UploadID: uploadIDs[9], + }, + }, + }, + // listMultipartResults - 34. + // checking listing with `KeyMarker` set. + { + MaxUploads: 10, + IsTruncated: false, + KeyMarker: objectNames[3], + Uploads: []uploadMetadata{ + { + Object: objectNames[4], + UploadID: uploadIDs[8], + }, + { + Object: objectNames[5], + UploadID: uploadIDs[9], + }, + }, + }, + // listMultipartResults - 35. + // Checking listing with `Prefix` and `KeyMarker`. + // No upload uploadMetadata in the result expected since KeyMarker is set to last Key in the result. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "minio-object", + KeyMarker: objectNames[1], + }, + // listMultipartResults - 36. + // checking listing with `Prefix` and `UploadIDMarker` set. + { + MaxUploads: 10, + IsTruncated: false, + Prefix: "minio", + UploadIDMarker: uploadIDs[4], + Uploads: []uploadMetadata{ + { + Object: objectNames[1], + UploadID: uploadIDs[5], + }, + }, + }, + // listMultipartResults - 37. + // Checking listing with `KeyMarker` and `UploadIDMarker` set. + { + MaxUploads: 10, + IsTruncated: false, + KeyMarker: "minio-object.txt", + UploadIDMarker: uploadIDs[5], + }, + } + + testCases := []struct { + // Inputs to ListObjects. + bucket string + prefix string + keyMarker string + uploadIDMarker string + delimiter string + maxUploads int + // Expected output of ListObjects. + expectedResult ListMultipartsInfo + expectedErr error + // Flag indicating whether the test is expected to pass or not. + shouldPass bool + }{ + // Test cases with invalid bucket names ( Test number 1-4 ). + {".test", "", "", "", "", 0, ListMultipartsInfo{}, BucketNameInvalid{Bucket: ".test"}, false}, + {"Test", "", "", "", "", 0, ListMultipartsInfo{}, BucketNameInvalid{Bucket: "Test"}, false}, + {"---", "", "", "", "", 0, ListMultipartsInfo{}, BucketNameInvalid{Bucket: "---"}, false}, + {"ad", "", "", "", "", 0, ListMultipartsInfo{}, BucketNameInvalid{Bucket: "ad"}, false}, + // Valid bucket names, but they donot exist (Test number 5-7). + {"volatile-bucket-1", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false}, + {"volatile-bucket-2", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false}, + {"volatile-bucket-3", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false}, + // Valid, existing bucket, but sending invalid delimeter values (Test number 8-9). + // Empty string < "" > and forward slash < / > are the ony two valid arguments for delimeter. + {bucketNames[0], "", "", "", "*", 0, ListMultipartsInfo{}, fmt.Errorf("delimiter '%s' is not supported", "*"), false}, + {bucketNames[0], "", "", "", "-", 0, ListMultipartsInfo{}, fmt.Errorf("delimiter '%s' is not supported", "-"), false}, + // Testing for failure cases with both perfix and marker (Test number 10). + // The prefix and marker combination to be valid it should satisy strings.HasPrefix(marker, prefix). + {bucketNames[0], "asia", "europe-object", "", "", 0, ListMultipartsInfo{}, + fmt.Errorf("Invalid combination of marker '%s' and prefix '%s'", "europe-object", "asia"), false}, + // Setting an invalid combination of uploadIDMarker and Marker (Test number 11-12). + {bucketNames[0], "asia", "asia/europe/", "abc", "", 0, ListMultipartsInfo{}, + fmt.Errorf("Invalid combination of uploadID marker '%s' and marker '%s'", "abc", "asia/europe/"), false}, + {bucketNames[0], "asia", "asia/europe", "abc", "", 0, ListMultipartsInfo{}, + fmt.Errorf("unknown UUID string %s", "abc"), false}, + + // Setting up valid case of ListMultiPartUploads. + // Test case with multiple parts for a single uploadID (Test number 13). + {bucketNames[0], "", "", "", "", 100, listMultipartResults[0], nil, true}, + // Test with a KeyMarker (Test number 14-17). + {bucketNames[0], "", "kin", "", "", 100, listMultipartResults[1], nil, true}, + {bucketNames[0], "", "orange", "", "", 100, listMultipartResults[2], nil, true}, + {bucketNames[0], "", "orange", "", "", 1, listMultipartResults[3], nil, true}, + {bucketNames[0], "", "min", "", "", 10, listMultipartResults[4], nil, true}, + // Test case with keyMarker set equal to number of parts in the result. (Test number 18). + {bucketNames[0], "", "min", "", "", 1, listMultipartResults[5], nil, true}, + // Test case with keyMarker set to 0. (Test number 19). + {bucketNames[0], "", "min", "", "", 0, listMultipartResults[6], nil, true}, + // Test case with keyMarker less than 0. (Test number 20). + {bucketNames[0], "", "min", "", "", -1, listMultipartResults[7], nil, true}, + // The result contains only one entry. The KeyPrefix is set to the object name in the result. + // Expecting the result to skip the KeyPrefix entry in the result (Test number 21). + {bucketNames[0], "", "minio-object", "", "", 2, listMultipartResults[8], nil, true}, + // Test case containing prefix values. + // Setting prefix to be equal to object name.(Test number 22). + {bucketNames[0], "minio-object", "", "", "", 2, listMultipartResults[9], nil, true}, + // Setting `prefix` to contain the object name as its prefix (Test number 23). + {bucketNames[0], "min", "", "", "", 2, listMultipartResults[10], nil, true}, + // Setting `prefix` to contain the object name as its prefix (Test number 24). + {bucketNames[0], "min", "", "", "", 1, listMultipartResults[11], nil, true}, + // Setting `prefix` to not to contain the object name as its prefix (Test number 25-26). + {bucketNames[0], "orange", "", "", "", 2, listMultipartResults[12], nil, true}, + {bucketNames[0], "Asia", "", "", "", 2, listMultipartResults[13], nil, true}, + // setting delimiter (Test number 27). + {bucketNames[0], "", "", "", "/", 2, listMultipartResults[14], nil, true}, + //Test case with multiple uploadID listing for given object (Test number 28). + {bucketNames[1], "", "", "", "", 100, listMultipartResults[15], nil, true}, + // Test case with multiple uploadID listing for given object, but uploadID marker set. + // Testing whether the marker entry is skipped (Test number 29-30). + {bucketNames[1], "", "", uploadIDs[1], "", 100, listMultipartResults[16], nil, true}, + {bucketNames[1], "", "", uploadIDs[2], "", 100, listMultipartResults[17], nil, true}, + // Test cases with multiple uploadID listing for a given object (Test number 31-32). + // MaxKeys set to values lesser than the number of entries in the uploadMetadata. + // IsTruncated is expected to be true. + {bucketNames[1], "", "", "", "", 2, listMultipartResults[18], nil, true}, + {bucketNames[1], "", "", "", "", 1, listMultipartResults[19], nil, true}, + // MaxKeys set to the value which is equal to no of entries in the uploadMetadata (Test number 33). + // In case of bucketNames[1], there are 3 entries. + // Since all available entries are listed, IsTruncated is expected to be false + // and NextMarkers are expected to empty. + {bucketNames[1], "", "", "", "", 3, listMultipartResults[20], nil, true}, + // Adding prefix (Test number 34-36). + {bucketNames[1], "min", "", "", "", 10, listMultipartResults[21], nil, true}, + {bucketNames[1], "orange", "", "", "", 10, listMultipartResults[22], nil, true}, + {bucketNames[1], "Asia", "", "", "", 10, listMultipartResults[23], nil, true}, + // Test case with `Prefix` and `UploadIDMarker` (Test number 37). + {bucketNames[1], "min", "", uploadIDs[0], "", 10, listMultipartResults[24], nil, true}, + // Test case with `KeyMarker` and `UploadIDMarker` (Test number 38). + {bucketNames[1], "", "minio-object", uploadIDs[0], "", 10, listMultipartResults[24], nil, true}, + + // Test case for bucket with multiple objects in it. + // Bucket used : `bucketNames[2]`. + // Objects used: `objectNames[1-5]`. + // UploadId's used: uploadIds[4-8]. + // (Test number 39). + {bucketNames[2], "", "", "", "", 100, listMultipartResults[25], nil, true}, + //Test cases with prefixes. + //Testing listing with prefix set to "min" (Test number 40) . + {bucketNames[2], "min", "", "", "", 100, listMultipartResults[26], nil, true}, + //Testing listing with prefix set to "ney" (Test number 41). + {bucketNames[2], "ney", "", "", "", 100, listMultipartResults[27], nil, true}, + //Testing listing with prefix set to "par" (Test number 42). + {bucketNames[2], "parrot", "", "", "", 100, listMultipartResults[28], nil, true}, + //Testing listing with prefix set to object name "neymar.jpeg" (Test number 43). + {bucketNames[2], "neymar.jpeg", "", "", "", 100, listMultipartResults[29], nil, true}, + // Testing listing with `MaxUploads` set to 3 (Test number 44). + {bucketNames[2], "", "", "", "", 3, listMultipartResults[30], nil, true}, + // In case of bucketNames[2], there are 6 entries (Test number 45). + // Since all available entries are listed, IsTruncated is expected to be false + // and NextMarkers are expected to empty. + {bucketNames[2], "", "", "", "", 6, listMultipartResults[31], nil, true}, + // Test case with `uploadIDMarker` (Test number 46). + {bucketNames[2], "", "", uploadIDs[6], "", 10, listMultipartResults[32], nil, true}, + // Test case with `KeyMarker` (Test number 47). + {bucketNames[2], "", objectNames[3], "", "", 10, listMultipartResults[33], nil, true}, + // Test case with `prefix` and `KeyMarker` (Test number 48). + {bucketNames[2], "minio-object", objectNames[1], "", "", 10, listMultipartResults[34], nil, true}, + // Test case with `prefix` and `uploadIDMarker` (Test number 49). + {bucketNames[2], "minio", "", uploadIDs[4], "", 10, listMultipartResults[35], nil, true}, + // Test case with `KeyMarker` and `uploadIDMarker` (Test number 50). + {bucketNames[2], "minio-object.txt", "", uploadIDs[5], "", 10, listMultipartResults[36], nil, true}, + } + + for i, testCase := range testCases { + actualResult, actualErr := obj.ListMultipartUploads(testCase.bucket, testCase.prefix, testCase.keyMarker, testCase.uploadIDMarker, testCase.delimiter, testCase.maxUploads) + if actualErr != nil && testCase.shouldPass { + t.Errorf("Test %d: %s: Expected to pass, but failed with: %s", i+1, instanceType, actualErr.Error()) + } + if actualErr == nil && !testCase.shouldPass { + t.Errorf("Test %d: %s: Expected to fail with \"%s\", but passed instead", i+1, instanceType, testCase.expectedErr.Error()) + } + // Failed as expected, but does it fail for the expected reason. + if actualErr != nil && !testCase.shouldPass { + if !strings.Contains(actualErr.Error(), testCase.expectedErr.Error()) { + t.Errorf("Test %d: %s: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, instanceType, testCase.expectedErr.Error(), actualErr.Error()) + } + } + // Passes as expected, but asserting the results. + if actualErr == nil && testCase.shouldPass { + expectedResult := testCase.expectedResult + // Asserting the MaxUploads. + if actualResult.MaxUploads != expectedResult.MaxUploads { + t.Errorf("Test %d: %s: Expected the MaxUploads to be %d, but instead found it to be %d", i+1, instanceType, expectedResult.MaxUploads, actualResult.MaxUploads) + } + // Asserting Prefix. + if actualResult.Prefix != expectedResult.Prefix { + t.Errorf("Test %d: %s: Expected Prefix to be \"%s\", but instead found it to be \"%s\"", i+1, instanceType, expectedResult.Prefix, actualResult.Prefix) + } + // Asserting Delimiter. + if actualResult.Delimiter != expectedResult.Delimiter { + t.Errorf("Test %d: %s: Expected Delimiter to be \"%s\", but instead found it to be \"%s\"", i+1, instanceType, expectedResult.Delimiter, actualResult.Delimiter) + } + // Asserting NextUploadIDMarker. + if actualResult.NextUploadIDMarker != expectedResult.NextUploadIDMarker { + t.Errorf("Test %d: %s: Expected NextUploadIDMarker to be \"%s\", but instead found it to be \"%s\"", i+1, instanceType, expectedResult.NextUploadIDMarker, actualResult.NextUploadIDMarker) + } + // Asserting NextKeyMarker. + if actualResult.NextKeyMarker != expectedResult.NextKeyMarker { + t.Errorf("Test %d: %s: Expected NextKeyMarker to be \"%s\", but instead found it to be \"%s\"", i+1, instanceType, expectedResult.NextKeyMarker, actualResult.NextKeyMarker) + } + // Asserting the keyMarker. + if actualResult.KeyMarker != expectedResult.KeyMarker { + t.Errorf("Test %d: %s: Expected keyMarker to be \"%s\", but instead found it to be \"%s\"", i+1, instanceType, expectedResult.KeyMarker, actualResult.KeyMarker) + } + // Asserting IsTruncated. + if actualResult.IsTruncated != testCase.expectedResult.IsTruncated { + t.Errorf("Test %d: %s: Expected Istruncated to be \"%v\", but found it to \"%v\"", i+1, instanceType, expectedResult.IsTruncated, actualResult.IsTruncated) + } + // Asserting the number of upload Metadata info. + if len(expectedResult.Uploads) != len(actualResult.Uploads) { + t.Errorf("Test %d: %s: Expected the result to contain info of %d Multipart Uploads, but found %d instead", i+1, instanceType, len(expectedResult.Uploads), len(actualResult.Uploads)) + } else { + // Iterating over the uploads Metadata and asserting the fields. + for j, actualMetaData := range actualResult.Uploads { + // Asserting the object name in the upload Metadata. + if actualMetaData.Object != expectedResult.Uploads[j].Object { + t.Errorf("Test %d: %s: Metadata %d: Expected Metadata Object to be \"%s\", but instead found \"%s\"", i+1, instanceType, j+1, expectedResult.Uploads[j].Object, actualMetaData.Object) + } + // Asserting the uploadID in the upload Metadata. + if actualMetaData.UploadID != expectedResult.Uploads[j].UploadID { + t.Errorf("Test %d: %s: Metadata %d: Expected Metadata UploadID to be \"%s\", but instead found \"%s\"", i+1, instanceType, j+1, expectedResult.Uploads[j].UploadID, actualMetaData.UploadID) + } + } + } + } + } +}