@ -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: <ERROR> %s" , i + 1 , instanceType , actualErr . Error ( ) )
}
if actualErr == nil && ! testCase . shouldPass {
t . Errorf ( "Test %d: %s: Expected to fail with <ERROR> \"%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 )
}
}
}
}
}
}