2015-10-16 14:26:01 -04:00
/ *
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
* Minio Cloud Storage , ( C ) 2015 , 2016 Minio , Inc .
2015-10-16 14:26:01 -04:00
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
2016-03-30 19:15:28 -04:00
package main
2015-10-16 14:26:01 -04:00
import (
"bytes"
"crypto/md5"
"encoding/hex"
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
2016-03-30 19:15:28 -04:00
"io"
2015-10-16 14:26:01 -04:00
"math/rand"
2016-04-22 21:16:02 -04:00
"runtime"
2015-10-16 14:26:01 -04:00
"strconv"
"gopkg.in/check.v1"
)
2016-04-22 19:19:45 -04:00
// TODO - enable all the commented tests.
2015-10-16 14:26:01 -04:00
// APITestSuite - collection of API tests
2016-04-22 13:24:04 -04:00
func APITestSuite ( c * check . C , create func ( ) objectAPI ) {
2015-10-16 14:26:01 -04:00
testMakeBucket ( c , create )
2016-04-22 21:16:02 -04:00
testMultipleObjectCreation ( c , create )
testPaging ( c , create )
testObjectOverwriteWorks ( c , create )
2015-10-16 14:26:01 -04:00
testNonExistantBucketOperations ( c , create )
testBucketRecreateFails ( c , create )
2016-04-22 21:16:02 -04:00
testPutObjectInSubdir ( c , create )
2015-10-16 14:26:01 -04:00
testListBuckets ( c , create )
testListBucketsOrder ( c , create )
testListObjectsTestsForNonExistantBucket ( c , create )
testNonExistantObjectInBucket ( c , create )
2016-04-22 21:16:02 -04:00
testGetDirectoryReturnsObjectNotFound ( c , create )
testDefaultContentType ( c , create )
testMultipartObjectCreation ( c , create )
testMultipartObjectAbort ( c , create )
2015-10-16 14:26:01 -04:00
}
2016-04-22 13:24:04 -04:00
func testMakeBucket ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
2016-04-22 19:19:45 -04:00
err := obj . MakeBucket ( "bucket-unknown" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
}
2016-04-22 13:24:04 -04:00
func testMultipartObjectCreation ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
uploadID , err := obj . NewMultipartUpload ( "bucket" , "key" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
completedParts := completeMultipartUpload { }
2015-10-16 14:26:01 -04:00
for i := 1 ; i <= 10 ; i ++ {
hasher := md5 . New ( )
2016-04-22 21:16:02 -04:00
hasher . Write ( [ ] byte ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) )
2016-03-12 19:08:15 -05:00
expectedMD5Sumhex := hex . EncodeToString ( hasher . Sum ( nil ) )
2015-10-16 14:26:01 -04:00
2016-03-12 19:08:15 -05:00
var calculatedMD5sum string
2016-04-22 21:16:02 -04:00
calculatedMD5sum , err = obj . PutObjectPart ( "bucket" , "key" , uploadID , i , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , expectedMD5Sumhex )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-12 19:08:15 -05:00
c . Assert ( calculatedMD5sum , check . Equals , expectedMD5Sumhex )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
completedParts . Parts = append ( completedParts . Parts , completePart { PartNumber : i , ETag : calculatedMD5sum } )
2015-10-16 14:26:01 -04:00
}
2016-04-16 15:48:41 -04:00
md5Sum , err := obj . CompleteMultipartUpload ( "bucket" , "key" , uploadID , completedParts . Parts )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
c . Assert ( md5Sum , check . Equals , "7dd76eded6f7c3580a78463a7cf539bd-10" )
2015-10-16 14:26:01 -04:00
}
2016-04-22 13:24:04 -04:00
func testMultipartObjectAbort ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
uploadID , err := obj . NewMultipartUpload ( "bucket" , "key" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
parts := make ( map [ int ] string )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
metadata := make ( map [ string ] string )
2015-10-16 14:26:01 -04:00
for i := 1 ; i <= 10 ; i ++ {
randomPerm := rand . Perm ( 10 )
randomString := ""
for _ , num := range randomPerm {
randomString = randomString + strconv . Itoa ( num )
}
hasher := md5 . New ( )
hasher . Write ( [ ] byte ( randomString ) )
2016-03-12 19:08:15 -05:00
expectedMD5Sumhex := hex . EncodeToString ( hasher . Sum ( nil ) )
2015-10-16 14:26:01 -04:00
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
metadata [ "md5" ] = expectedMD5Sumhex
2016-03-12 19:08:15 -05:00
var calculatedMD5sum string
2016-04-12 15:45:15 -04:00
calculatedMD5sum , err = obj . PutObjectPart ( "bucket" , "key" , uploadID , i , int64 ( len ( randomString ) ) , bytes . NewBufferString ( randomString ) , expectedMD5Sumhex )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-12 19:08:15 -05:00
c . Assert ( calculatedMD5sum , check . Equals , expectedMD5Sumhex )
parts [ i ] = expectedMD5Sumhex
2015-10-16 14:26:01 -04:00
}
2016-04-12 15:45:15 -04:00
err = obj . AbortMultipartUpload ( "bucket" , "key" , uploadID )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
}
2016-04-22 13:24:04 -04:00
func testMultipleObjectCreation ( c * check . C , create func ( ) objectAPI ) {
2015-10-16 14:26:01 -04:00
objects := make ( map [ string ] [ ] byte )
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
for i := 0 ; i < 10 ; i ++ {
2016-04-22 21:16:02 -04:00
randomPerm := rand . Perm ( 100 )
2015-10-16 14:26:01 -04:00
randomString := ""
for _ , num := range randomPerm {
randomString = randomString + strconv . Itoa ( num )
}
hasher := md5 . New ( )
hasher . Write ( [ ] byte ( randomString ) )
2016-03-12 19:08:15 -05:00
expectedMD5Sumhex := hex . EncodeToString ( hasher . Sum ( nil ) )
2015-10-16 14:26:01 -04:00
key := "obj" + strconv . Itoa ( i )
objects [ key ] = [ ] byte ( randomString )
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
2016-03-30 19:15:28 -04:00
metadata := make ( map [ string ] string )
metadata [ "md5Sum" ] = expectedMD5Sumhex
2016-04-16 15:48:41 -04:00
md5Sum , err := obj . PutObject ( "bucket" , key , int64 ( len ( randomString ) ) , bytes . NewBufferString ( randomString ) , metadata )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-16 15:48:41 -04:00
c . Assert ( md5Sum , check . Equals , expectedMD5Sumhex )
2015-10-16 14:26:01 -04:00
}
for key , value := range objects {
var byteBuffer bytes . Buffer
2016-04-12 15:45:15 -04:00
r , err := obj . GetObject ( "bucket" , key , 0 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
_ , e := io . Copy ( & byteBuffer , r )
c . Assert ( e , check . IsNil )
2015-10-16 14:26:01 -04:00
c . Assert ( byteBuffer . Bytes ( ) , check . DeepEquals , value )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
c . Assert ( r . Close ( ) , check . IsNil )
2015-10-16 14:26:01 -04:00
2016-04-12 15:45:15 -04:00
objInfo , err := obj . GetObjectInfo ( "bucket" , key )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
c . Assert ( objInfo . Size , check . Equals , int64 ( len ( value ) ) )
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
2016-03-30 19:15:28 -04:00
r . Close ( )
2015-10-16 14:26:01 -04:00
}
}
2016-04-22 13:24:04 -04:00
func testPaging ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
obj . MakeBucket ( "bucket" )
result , err := obj . ListObjects ( "bucket" , "" , "" , "" , 0 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-01-19 20:49:48 -05:00
c . Assert ( len ( result . Objects ) , check . Equals , 0 )
c . Assert ( result . IsTruncated , check . Equals , false )
2015-10-16 14:26:01 -04:00
// check before paging occurs
for i := 0 ; i < 5 ; i ++ {
key := "obj" + strconv . Itoa ( i )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , key , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2016-03-01 18:59:16 -05:00
c . Assert ( err , check . IsNil )
2016-04-26 13:35:39 -04:00
result , err = obj . ListObjects ( "bucket" , "" , "" , "" , 5 )
c . Assert ( err , check . IsNil )
c . Assert ( len ( result . Objects ) , check . Equals , i + 1 )
c . Assert ( result . IsTruncated , check . Equals , false )
2015-10-16 14:26:01 -04:00
}
// check after paging occurs pages work
for i := 6 ; i <= 10 ; i ++ {
key := "obj" + strconv . Itoa ( i )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , key , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-26 13:35:39 -04:00
result , err = obj . ListObjects ( "bucket" , "obj" , "" , "" , 5 )
c . Assert ( err , check . IsNil )
c . Assert ( len ( result . Objects ) , check . Equals , 5 )
c . Assert ( result . IsTruncated , check . Equals , true )
2015-10-16 14:26:01 -04:00
}
// check paging with prefix at end returns less objects
{
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "newPrefix" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "newPrefix2" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-26 13:35:39 -04:00
result , err = obj . ListObjects ( "bucket" , "new" , "" , "" , 5 )
c . Assert ( err , check . IsNil )
c . Assert ( len ( result . Objects ) , check . Equals , 2 )
2015-10-16 14:26:01 -04:00
}
// check ordering of pages
{
2016-04-12 15:45:15 -04:00
result , err = obj . ListObjects ( "bucket" , "" , "" , "" , 1000 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-11 19:31:24 -05:00
c . Assert ( result . Objects [ 0 ] . Name , check . Equals , "newPrefix" )
c . Assert ( result . Objects [ 1 ] . Name , check . Equals , "newPrefix2" )
c . Assert ( result . Objects [ 2 ] . Name , check . Equals , "obj0" )
c . Assert ( result . Objects [ 3 ] . Name , check . Equals , "obj1" )
c . Assert ( result . Objects [ 4 ] . Name , check . Equals , "obj10" )
2015-10-16 14:26:01 -04:00
}
// check delimited results with delimiter and prefix
{
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "this/is/delimited" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "this/is/also/a/delimited/file" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
result , err = obj . ListObjects ( "bucket" , "this/is/" , "" , "/" , 10 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-01-19 20:49:48 -05:00
c . Assert ( len ( result . Objects ) , check . Equals , 1 )
c . Assert ( result . Prefixes [ 0 ] , check . Equals , "this/is/also/" )
2015-10-16 14:26:01 -04:00
}
// check delimited results with delimiter without prefix
{
2016-04-12 15:45:15 -04:00
result , err = obj . ListObjects ( "bucket" , "" , "" , "/" , 1000 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-11 19:31:24 -05:00
c . Assert ( result . Objects [ 0 ] . Name , check . Equals , "newPrefix" )
c . Assert ( result . Objects [ 1 ] . Name , check . Equals , "newPrefix2" )
c . Assert ( result . Objects [ 2 ] . Name , check . Equals , "obj0" )
c . Assert ( result . Objects [ 3 ] . Name , check . Equals , "obj1" )
c . Assert ( result . Objects [ 4 ] . Name , check . Equals , "obj10" )
2016-01-19 20:49:48 -05:00
c . Assert ( result . Prefixes [ 0 ] , check . Equals , "this/" )
2015-10-16 14:26:01 -04:00
}
// check results with Marker
{
2016-04-26 13:35:39 -04:00
result , err = obj . ListObjects ( "bucket" , "" , "newPrefix" , "" , 3 )
c . Assert ( err , check . IsNil )
c . Assert ( result . Objects [ 0 ] . Name , check . Equals , "newPrefix2" )
c . Assert ( result . Objects [ 1 ] . Name , check . Equals , "obj0" )
c . Assert ( result . Objects [ 2 ] . Name , check . Equals , "obj1" )
2015-10-16 14:26:01 -04:00
}
// check ordering of results with prefix
{
2016-04-12 15:45:15 -04:00
result , err = obj . ListObjects ( "bucket" , "obj" , "" , "" , 1000 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-11 19:31:24 -05:00
c . Assert ( result . Objects [ 0 ] . Name , check . Equals , "obj0" )
c . Assert ( result . Objects [ 1 ] . Name , check . Equals , "obj1" )
c . Assert ( result . Objects [ 2 ] . Name , check . Equals , "obj10" )
c . Assert ( result . Objects [ 3 ] . Name , check . Equals , "obj2" )
c . Assert ( result . Objects [ 4 ] . Name , check . Equals , "obj3" )
2015-10-16 14:26:01 -04:00
}
// check ordering of results with prefix and no paging
{
2016-04-12 15:45:15 -04:00
result , err = obj . ListObjects ( "bucket" , "new" , "" , "" , 5 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-11 19:31:24 -05:00
c . Assert ( result . Objects [ 0 ] . Name , check . Equals , "newPrefix" )
c . Assert ( result . Objects [ 1 ] . Name , check . Equals , "newPrefix2" )
2015-10-16 14:26:01 -04:00
}
}
2016-04-22 13:24:04 -04:00
func testObjectOverwriteWorks ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "object" , int64 ( len ( "The list of parts was not in ascending order. The parts list must be specified in order by part number." ) ) , bytes . NewBufferString ( "The list of parts was not in ascending order. The parts list must be specified in order by part number." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "object" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
var bytesBuffer bytes . Buffer
2016-04-12 15:45:15 -04:00
r , err := obj . GetObject ( "bucket" , "object" , 0 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
_ , e := io . Copy ( & bytesBuffer , r )
c . Assert ( e , check . IsNil )
2016-04-22 21:16:02 -04:00
if runtime . GOOS != "windows" {
c . Assert ( string ( bytesBuffer . Bytes ( ) ) , check . Equals , "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." )
}
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
c . Assert ( r . Close ( ) , check . IsNil )
2015-10-16 14:26:01 -04:00
}
2016-04-22 13:24:04 -04:00
func testNonExistantBucketOperations ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
2016-04-22 19:19:45 -04:00
_ , err := obj . PutObject ( "bucket1" , "object" , int64 ( len ( "one" ) ) , bytes . NewBufferString ( "one" ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . Not ( check . IsNil ) )
}
2016-04-22 13:24:04 -04:00
func testBucketRecreateFails ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "string" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
err = obj . MakeBucket ( "string" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . Not ( check . IsNil ) )
}
2016-04-22 13:24:04 -04:00
func testPutObjectInSubdir ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "dir1/dir2/object" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
var bytesBuffer bytes . Buffer
2016-04-12 15:45:15 -04:00
r , err := obj . GetObject ( "bucket" , "dir1/dir2/object" , 0 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
n , e := io . Copy ( & bytesBuffer , r )
c . Assert ( e , check . IsNil )
2016-04-22 21:16:02 -04:00
c . Assert ( len ( bytesBuffer . Bytes ( ) ) , check . Equals , len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
c . Assert ( int64 ( len ( bytesBuffer . Bytes ( ) ) ) , check . Equals , int64 ( n ) )
c . Assert ( r . Close ( ) , check . IsNil )
2015-10-16 14:26:01 -04:00
}
2016-04-22 13:24:04 -04:00
func testListBuckets ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
2015-10-16 14:26:01 -04:00
// test empty list
2016-04-12 15:45:15 -04:00
buckets , err := obj . ListBuckets ( )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
c . Assert ( len ( buckets ) , check . Equals , 0 )
// add one and test exists
2016-04-12 15:45:15 -04:00
err = obj . MakeBucket ( "bucket1" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
buckets , err = obj . ListBuckets ( )
2015-10-16 14:26:01 -04:00
c . Assert ( len ( buckets ) , check . Equals , 1 )
c . Assert ( err , check . IsNil )
// add two and test exists
2016-04-12 15:45:15 -04:00
err = obj . MakeBucket ( "bucket2" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
buckets , err = obj . ListBuckets ( )
2015-10-16 14:26:01 -04:00
c . Assert ( len ( buckets ) , check . Equals , 2 )
c . Assert ( err , check . IsNil )
// add three and test exists + prefix
2016-04-12 15:45:15 -04:00
err = obj . MakeBucket ( "bucket22" )
2015-10-16 14:26:01 -04:00
2016-04-12 15:45:15 -04:00
buckets , err = obj . ListBuckets ( )
2015-10-16 14:26:01 -04:00
c . Assert ( len ( buckets ) , check . Equals , 3 )
c . Assert ( err , check . IsNil )
}
2016-04-22 13:24:04 -04:00
func testListBucketsOrder ( c * check . C , create func ( ) objectAPI ) {
2015-10-16 14:26:01 -04:00
// if implementation contains a map, order of map keys will vary.
// this ensures they return in the same order each time
for i := 0 ; i < 10 ; i ++ {
2016-04-12 15:45:15 -04:00
obj := create ( )
2015-10-16 14:26:01 -04:00
// add one and test exists
2016-04-12 15:45:15 -04:00
err := obj . MakeBucket ( "bucket1" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
err = obj . MakeBucket ( "bucket2" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
buckets , err := obj . ListBuckets ( )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
c . Assert ( len ( buckets ) , check . Equals , 2 )
c . Assert ( buckets [ 0 ] . Name , check . Equals , "bucket1" )
c . Assert ( buckets [ 1 ] . Name , check . Equals , "bucket2" )
}
}
2016-04-22 13:24:04 -04:00
func testListObjectsTestsForNonExistantBucket ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
result , err := obj . ListObjects ( "bucket" , "" , "" , "" , 1000 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . Not ( check . IsNil ) )
2016-01-19 20:49:48 -05:00
c . Assert ( result . IsTruncated , check . Equals , false )
c . Assert ( len ( result . Objects ) , check . Equals , 0 )
2015-10-16 14:26:01 -04:00
}
2016-04-22 13:24:04 -04:00
func testNonExistantObjectInBucket ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
_ , err = obj . GetObject ( "bucket" , "dir1" , 0 )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . Not ( check . IsNil ) )
switch err := err . ToGoError ( ) . ( type ) {
case ObjectNotFound :
c . Assert ( err , check . ErrorMatches , "Object not found: bucket#dir1" )
default :
c . Assert ( err , check . Equals , "fails" )
}
}
2016-04-22 13:24:04 -04:00
func testGetDirectoryReturnsObjectNotFound ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "dir1/dir3/object" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "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." ) , nil )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
_ , err = obj . GetObject ( "bucket" , "dir1" , 0 )
2015-10-16 14:26:01 -04:00
switch err := err . ToGoError ( ) . ( type ) {
2016-04-25 13:39:28 -04:00
case ObjectNotFound :
2015-10-16 14:26:01 -04:00
c . Assert ( err . Bucket , check . Equals , "bucket" )
2016-04-08 13:37:38 -04:00
c . Assert ( err . Object , check . Equals , "dir1" )
2015-10-16 14:26:01 -04:00
default :
// force a failure with a line number
2016-04-25 13:39:28 -04:00
c . Assert ( err , check . Equals , "ObjectNotFound" )
2015-10-16 14:26:01 -04:00
}
2016-04-12 15:45:15 -04:00
_ , err = obj . GetObject ( "bucket" , "dir1/" , 0 )
2015-10-16 14:26:01 -04:00
switch err := err . ToGoError ( ) . ( type ) {
2016-04-25 13:39:28 -04:00
case ObjectNotFound :
2015-10-16 14:26:01 -04:00
c . Assert ( err . Bucket , check . Equals , "bucket" )
2016-04-08 13:37:38 -04:00
c . Assert ( err . Object , check . Equals , "dir1/" )
2015-10-16 14:26:01 -04:00
default :
// force a failure with a line number
2016-04-25 13:39:28 -04:00
c . Assert ( err , check . Equals , "ObjectNotFound" )
2015-10-16 14:26:01 -04:00
}
}
2016-04-22 13:24:04 -04:00
func testDefaultContentType ( c * check . C , create func ( ) objectAPI ) {
2016-04-12 15:45:15 -04:00
obj := create ( )
err := obj . MakeBucket ( "bucket" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
2016-03-12 19:08:15 -05:00
// Test empty
2016-04-22 21:16:02 -04:00
_ , err = obj . PutObject ( "bucket" , "one" , int64 ( len ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) ) , bytes . NewBufferString ( "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." ) , nil )
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
2016-04-03 04:34:20 -04:00
c . Assert ( err , check . IsNil )
2016-04-12 15:45:15 -04:00
objInfo , err := obj . GetObjectInfo ( "bucket" , "one" )
2015-10-16 14:26:01 -04:00
c . Assert ( err , check . IsNil )
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
2016-03-30 19:15:28 -04:00
c . Assert ( objInfo . ContentType , check . Equals , "application/octet-stream" )
2015-10-16 14:26:01 -04:00
}