2015-07-12 15:40:38 -04:00
/ *
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-12 18:27:10 -05:00
* Minio Cloud Storage , ( C ) 2015 , 2016 Minio , Inc .
2015-07-12 15:40:38 -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 .
* /
2015-09-19 03:52:01 -04:00
package main
2015-07-12 15:40:38 -04:00
import (
"bytes"
2016-04-11 04:29:18 -04:00
"crypto/md5"
2016-06-21 15:10:18 -04:00
"encoding/base64"
2016-06-25 06:03:27 -04:00
"encoding/hex"
2016-06-21 15:10:18 -04:00
"encoding/xml"
2016-06-13 05:53:09 -04:00
"fmt"
2015-07-12 15:40:38 -04:00
"io/ioutil"
2016-06-25 06:03:27 -04:00
"math/rand"
2016-06-21 15:10:18 -04:00
"net/http"
2015-07-12 15:40:38 -04:00
"strings"
2016-03-07 22:07:43 -05:00
"sync"
2015-09-20 15:44:44 -04:00
"time"
2015-07-12 15:40:38 -04:00
2015-08-22 21:34:00 -04:00
. "gopkg.in/check.v1"
2015-07-12 15:40:38 -04:00
)
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
// API suite container.
type MyAPISuite struct {
2016-06-21 15:10:18 -04:00
testServer TestServer
2015-07-12 15:40:38 -04:00
}
2016-06-21 15:10:18 -04:00
// Initializing the test suite.
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
var _ = Suite ( & MyAPISuite { } )
2015-07-12 15:40:38 -04:00
2016-06-21 15:10:18 -04:00
// Setting up the test suite.
// Starting the Test server with temporary FS backend.
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
func ( s * MyAPISuite ) SetUpSuite ( c * C ) {
2016-06-21 15:10:18 -04:00
s . testServer = StartTestServer ( c , "FS" )
2015-07-12 15:40:38 -04:00
}
2016-06-21 15:10:18 -04:00
// Called implicitly by "gopkg.in/check.v1" after all tests are run.
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
func ( s * MyAPISuite ) TearDownSuite ( c * C ) {
2016-06-21 15:10:18 -04:00
s . testServer . Stop ( )
2016-06-20 09:18:47 -04:00
}
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
func ( s * MyAPISuite ) TestAuth ( c * C ) {
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-12 18:27:10 -05:00
secretID , err := genSecretAccessKey ( )
2015-10-16 14:26:01 -04:00
c . Assert ( err , IsNil )
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-12 18:27:10 -05:00
accessID , err := genAccessKeyID ( )
2015-10-16 14:26:01 -04:00
c . Assert ( err , IsNil )
c . Assert ( len ( secretID ) , Equals , minioSecretID )
c . Assert ( len ( accessID ) , Equals , minioAccessID )
}
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
func ( s * MyAPISuite ) TestBucketPolicy ( c * C ) {
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
2016-03-15 13:38:04 -04:00
// Sample bucket policy.
bucketPolicyBuf := ` {
"Version" : "2012-10-17" ,
"Statement" : [
{
"Action" : [
"s3:GetBucketLocation" ,
"s3:ListBucket"
] ,
"Effect" : "Allow" ,
"Principal" : {
"AWS" : [
"*"
]
} ,
"Resource" : [
"arn:aws:s3:::policybucket"
]
} ,
{
"Action" : [
"s3:GetObject"
] ,
"Effect" : "Allow" ,
"Principal" : {
"AWS" : [
"*"
]
} ,
"Resource" : [
"arn:aws:s3:::policybucket/this*"
]
}
]
} `
// Put a new bucket policy.
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/policybucket?policy" ,
int64 ( len ( bucketPolicyBuf ) ) , bytes . NewReader ( [ ] byte ( bucketPolicyBuf ) ) , s . testServer . AccessKey , s . testServer . SecretKey )
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
2016-03-15 13:38:04 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
// Fetch the uploaded policy.
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/policybucket?policy" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
2016-03-15 13:38:04 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
bucketPolicyReadBuf , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
// Verify if downloaded policy matches with previousy uploaded.
c . Assert ( bytes . Equal ( [ ] byte ( bucketPolicyBuf ) , bucketPolicyReadBuf ) , Equals , true )
// Delete policy.
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/policybucket?policy" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
2016-03-15 13:38:04 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
2016-05-02 19:58:10 -04:00
// Verify if the policy was indeed deleted.
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/policybucket?policy" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-02 19:58:10 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNotFound )
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
2016-03-15 13:38:04 -04:00
}
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
func ( s * MyAPISuite ) TestDeleteBucket ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/deletebucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-16 17:08:33 -04:00
c . Assert ( err , IsNil )
2015-10-16 14:26:01 -04:00
client := http . Client { }
2015-07-16 17:08:33 -04:00
response , err := client . Do ( request )
c . Assert ( err , IsNil )
2015-10-16 14:26:01 -04:00
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/deletebucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-10-16 14:26:01 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2015-10-16 23:02:37 -04:00
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
2015-07-16 17:08:33 -04:00
}
2016-05-05 04:35:21 -04:00
func ( s * MyAPISuite ) TestDeleteBucketNotEmpty ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/deletebucket-notempty" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-05 04:35:21 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/deletebucket-notempty/myobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-05 04:35:21 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/deletebucket-notempty" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-05 04:35:21 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusConflict )
}
2016-05-14 18:47:19 -04:00
// Tests delete object responses and success.
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
func ( s * MyAPISuite ) TestDeleteObject ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/deletebucketobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-16 17:08:33 -04:00
c . Assert ( err , IsNil )
2015-10-16 14:26:01 -04:00
client := http . Client { }
2015-07-16 17:08:33 -04:00
response , err := client . Do ( request )
c . Assert ( err , IsNil )
2015-10-16 14:26:01 -04:00
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/deletebucketobject/prefix/myobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-10-16 14:26:01 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-17 01:18:43 -04:00
// Should not delete "prefix/myobject"
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/deletebucketobject/prefix" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-06-17 01:18:43 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/deletebucketobject/prefix/myobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-10-16 14:26:01 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2015-10-16 23:02:37 -04:00
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
2016-05-14 18:47:19 -04:00
2016-05-14 20:18:00 -04:00
// Delete non existent object should return http.StatusNoContent.
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/deletebucketobject/prefix/myobject1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-14 18:47:19 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNoContent )
2015-07-16 17:08:33 -04:00
}
2016-05-14 20:18:00 -04:00
func ( s * MyAPISuite ) TestNonExistentBucket ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "HEAD" , s . testServer . Server . URL + "/nonexistentbucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNotFound )
}
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
func ( s * MyAPISuite ) TestEmptyObject ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/emptyobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/emptyobject/object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/emptyobject/object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
responseBody , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( true , Equals , bytes . Equal ( responseBody , buffer . Bytes ( ) ) )
}
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
func ( s * MyAPISuite ) TestBucket ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/bucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/bucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
}
2016-05-28 18:13:15 -04:00
func ( s * MyAPISuite ) TestObjectGet ( c * C ) {
2015-07-12 15:40:38 -04:00
buffer := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/testobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/testobject/object" , int64 ( buffer . Len ( ) ) , buffer , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/testobject/object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
responseBody , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( responseBody , DeepEquals , [ ] byte ( "hello world" ) )
}
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
func ( s * MyAPISuite ) TestMultipleObjects ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/multipleobjects" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/multipleobjects/object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchKey" , "The specified key does not exist." , http . StatusNotFound )
//// test object 1
// get object
buffer1 := bytes . NewReader ( [ ] byte ( "hello one" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/multipleobjects/object1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/multipleobjects/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// verify response data
responseBody , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( true , Equals , bytes . Equal ( responseBody , [ ] byte ( "hello one" ) ) )
buffer2 := bytes . NewReader ( [ ] byte ( "hello two" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/multipleobjects/object2" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/multipleobjects/object2" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// verify response data
responseBody , err = ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( true , Equals , bytes . Equal ( responseBody , [ ] byte ( "hello two" ) ) )
buffer3 := bytes . NewReader ( [ ] byte ( "hello three" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/multipleobjects/object3" ,
int64 ( buffer3 . Len ( ) ) , buffer3 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/multipleobjects/object3" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// verify object
responseBody , err = ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( true , Equals , bytes . Equal ( responseBody , [ ] byte ( "hello three" ) ) )
}
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
func ( s * MyAPISuite ) TestNotImplemented ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/bucket/object?policy" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNotImplemented )
}
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
func ( s * MyAPISuite ) TestHeader ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/bucket/object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchKey" , "The specified key does not exist." , http . StatusNotFound )
}
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
func ( s * MyAPISuite ) TestPutBucket ( c * C ) {
2016-03-07 22:07:43 -05:00
// Block 1: Testing for racey access
// The assertion is removed from this block since the purpose of this block is to find races
// The purpose this block is not to check for correctness of functionality
// Run the test with -race flag to utilize this
var wg sync . WaitGroup
for i := 0 ; i < ConcurrencyLevel ; i ++ {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-bucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-03-07 22:07:43 -05:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
defer response . Body . Close ( )
} ( )
}
wg . Wait ( )
//Block 2: testing for correctness of the functionality
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-bucket-slash/" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-03-07 22:07:43 -05:00
response . Body . Close ( )
2015-10-25 11:00:39 -04:00
2015-07-12 15:40:38 -04:00
}
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
func ( s * MyAPISuite ) TestCopyObject ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-copy" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-27 06:04:52 -05:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-copy/object" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-27 06:04:52 -05:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-copy/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-27 06:04:52 -05:00
request . Header . Set ( "X-Amz-Copy-Source" , "/put-object-copy/object" )
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/put-object-copy/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-27 06:04:52 -05:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
object , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( string ( object ) , Equals , "hello world" )
}
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
func ( s * MyAPISuite ) TestPutObject ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object/object" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
}
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
func ( s * MyAPISuite ) TestListBuckets ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2015-09-19 03:52:01 -04:00
var results ListBucketsResponse
2015-07-12 15:40:38 -04:00
decoder := xml . NewDecoder ( response . Body )
err = decoder . Decode ( & results )
c . Assert ( err , IsNil )
}
2016-06-13 05:53:09 -04:00
// Tests put object with long names.
func ( s * MyAPISuite ) TestPutObjectLongName ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-long-name" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-06-13 05:53:09 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer := bytes . NewReader ( [ ] byte ( "hello world" ) )
longObjName := fmt . Sprintf ( "%0255d/%0255d/%0255d" , 1 , 1 , 1 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-long-name/" + longObjName ,
int64 ( buffer . Len ( ) ) , buffer , s . testServer . AccessKey , s . testServer . SecretKey )
2016-06-13 05:53:09 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
longObjName = fmt . Sprintf ( "%0256d" , 1 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/put-object-long-name/" + longObjName ,
int64 ( buffer . Len ( ) ) , buffer , s . testServer . AccessKey , s . testServer . SecretKey )
2016-06-13 05:53:09 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNotFound )
}
2016-05-14 20:18:00 -04:00
func ( s * MyAPISuite ) TestNotBeAbleToCreateObjectInNonexistentBucket ( c * C ) {
2015-07-12 15:40:38 -04:00
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/innonexistentbucket/object" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchBucket" , "The specified bucket does not exist." , http . StatusNotFound )
}
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
func ( s * MyAPISuite ) TestHeadOnObject ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/headonobject" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/headonobject/object1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/headonobject/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-02-28 21:10:37 -05:00
lastModified := response . Header . Get ( "Last-Modified" )
t , err := time . Parse ( http . TimeFormat , lastModified )
c . Assert ( err , IsNil )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/headonobject/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-28 21:10:37 -05:00
c . Assert ( err , IsNil )
request . Header . Set ( "If-Modified-Since" , t . Add ( 1 * time . Minute ) . UTC ( ) . Format ( http . TimeFormat ) )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusNotModified )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/headonobject/object1" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-02-28 21:10:37 -05:00
c . Assert ( err , IsNil )
request . Header . Set ( "If-Unmodified-Since" , t . Add ( - 1 * time . Minute ) . UTC ( ) . Format ( http . TimeFormat ) )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusPreconditionFailed )
2015-07-12 15:40:38 -04:00
}
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
func ( s * MyAPISuite ) TestHeadOnBucket ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/headonbucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/headonbucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
}
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
func ( s * MyAPISuite ) TestXMLNameNotInBucketListJson ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
request . Header . Add ( "Accept" , "application/json" )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
byteResults , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( strings . Contains ( string ( byteResults ) , "XML" ) , Equals , false )
}
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
func ( s * MyAPISuite ) TestXMLNameNotInObjectListJson ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/xmlnamenotinobjectlistjson" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
request . Header . Add ( "Accept" , "application/json" )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/xmlnamenotinobjectlistjson" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
request . Header . Add ( "Accept" , "application/json" )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
byteResults , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( strings . Contains ( string ( byteResults ) , "XML" ) , Equals , false )
}
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
func ( s * MyAPISuite ) TestContentTypePersists ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/contenttype-persists" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/contenttype-persists/minio.png" , int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
delete ( request . Header , "Content-Type" )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/contenttype-persists/minio.png" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2016-06-17 00:42:02 -04:00
c . Assert ( response . Header . Get ( "Content-Type" ) , Equals , "image/png" )
2015-07-12 15:40:38 -04:00
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/contenttype-persists/minio.png" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-17 00:42:02 -04:00
c . Assert ( response . Header . Get ( "Content-Type" ) , Equals , "image/png" )
2015-07-12 15:40:38 -04:00
buffer2 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/contenttype-persists/minio.json" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
delete ( request . Header , "Content-Type" )
request . Header . Add ( "Content-Type" , "application/json" )
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "HEAD" , s . testServer . Server . URL + "/contenttype-persists/minio.json" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2016-06-17 00:42:02 -04:00
c . Assert ( response . Header . Get ( "Content-Type" ) , Equals , "application/json" )
2015-07-12 15:40:38 -04:00
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/contenttype-persists/minio.json" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2016-06-17 00:42:02 -04:00
c . Assert ( response . Header . Get ( "Content-Type" ) , Equals , "application/json" )
2015-07-12 15:40:38 -04:00
}
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
func ( s * MyAPISuite ) TestPartialContent ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/partial-content" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "Hello World" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/partial-content/bar" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
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
// Prepare request
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/partial-content/bar" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
request . Header . Add ( "Range" , "bytes=6-7" )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusPartialContent )
partialObject , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
c . Assert ( string ( partialObject ) , Equals , "Wo" )
}
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
func ( s * MyAPISuite ) TestListObjectsHandlerErrors ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/objecthandlererrors-." ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "InvalidBucketName" , "The specified bucket is not valid." , http . StatusBadRequest )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/objecthandlererrors" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchBucket" , "The specified bucket does not exist." , http . StatusNotFound )
2015-07-16 20:32:33 -04:00
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objecthandlererrors" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-16 20:32:33 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/objecthandlererrors?max-keys=-2" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-16 20:32:33 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2015-09-18 17:48:01 -04:00
verifyError ( c , response , "InvalidArgument" , "Argument maxKeys must be an integer between 0 and 2147483647." , http . StatusBadRequest )
2015-07-12 15:40:38 -04:00
}
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
func ( s * MyAPISuite ) TestPutBucketErrors ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/putbucket-." ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "InvalidBucketName" , "The specified bucket is not valid." , http . StatusBadRequest )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/putbucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/putbucket" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2016-05-03 06:19:04 -04:00
verifyError ( c , response , "BucketAlreadyOwnedByYou" , "Your previous request to create the named bucket succeeded and you already own it." , http . StatusConflict )
2015-07-12 15:40:38 -04:00
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/putbucket?acl" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NotImplemented" , "A header you provided implies functionality that is not implemented." , http . StatusNotImplemented )
}
2016-06-25 06:03:27 -04:00
func ( s * MyAPISuite ) TestGetObjectLarge10MiB ( c * C ) {
// Make bucket for this test.
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-10" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
line := "1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123"
// Create 10MiB content where each line contains 1024 characters.
for i := 0 ; i < 10 * 1024 ; i ++ {
buffer . WriteString ( fmt . Sprintf ( "[%05d] %s\n" , i , line ) )
}
putContent := buffer . String ( )
// Put object
buf := bytes . NewReader ( [ ] byte ( putContent ) )
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-10/big-file-10" ,
int64 ( buf . Len ( ) ) , buf , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// Get object
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/test-bucket-10/big-file-10" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
getContent , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
// Compare putContent and getContent
c . Assert ( string ( getContent ) , Equals , putContent )
}
func ( s * MyAPISuite ) TestGetObjectLarge11MiB ( c * C ) {
// Make bucket for this test.
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-11" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
line := "1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123"
// Create 11MiB content where each line contains 1024 characters.
for i := 0 ; i < 11 * 1024 ; i ++ {
buffer . WriteString ( fmt . Sprintf ( "[%05d] %s\n" , i , line ) )
}
putMD5 := sumMD5 ( buffer . Bytes ( ) )
// Put object
buf := bytes . NewReader ( buffer . Bytes ( ) )
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-11/big-file-11" ,
int64 ( buf . Len ( ) ) , buf , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// Get object
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/test-bucket-11/big-file-11" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
getContent , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
getMD5 := sumMD5 ( getContent ) // Get md5.
// Compare putContent and getContent
c . Assert ( hex . EncodeToString ( putMD5 ) , Equals , hex . EncodeToString ( getMD5 ) )
}
// TestGetPartialObjectMisAligned - tests get object partially mis-aligned.
func ( s * MyAPISuite ) TestGetPartialObjectMisAligned ( c * C ) {
// Make bucket for this test.
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-align" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
line := "1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123"
rand . Seed ( time . Now ( ) . UTC ( ) . UnixNano ( ) )
// Create a misalgined data.
for i := 0 ; i < 13 * rand . Intn ( 1 << 16 ) ; i ++ {
buffer . WriteString ( fmt . Sprintf ( "[%05d] %s\n" , i , line [ : rand . Intn ( 1 << 8 ) ] ) )
}
putContent := buffer . String ( )
// Put object
buf := bytes . NewReader ( [ ] byte ( putContent ) )
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-align/big-file-13" ,
int64 ( buf . Len ( ) ) , buf , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// Prepare request
var testCases = [ ] struct {
byteRange string
expectedString string
} {
{ "10-11" , putContent [ 10 : 12 ] } ,
{ "1-" , putContent [ 1 : ] } ,
{ "6-" , putContent [ 6 : ] } ,
{ "-2" , putContent [ len ( putContent ) - 2 : ] } ,
{ "-7" , putContent [ len ( putContent ) - 7 : ] } ,
}
for _ , t := range testCases {
// Get object
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/test-bucket-align/big-file-13" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
// Get a different byte range.
request . Header . Add ( "Range" , "bytes=" + t . byteRange )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusPartialContent )
getContent , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
// Compare putContent and getContent
c . Assert ( string ( getContent ) , Equals , t . expectedString )
}
}
func ( s * MyAPISuite ) TestGetPartialObjectLarge11MiB ( c * C ) {
// Make bucket for this test.
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-11p" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
line := "1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123"
// Create 11MiB content where each line contains 1024
// characters.
for i := 0 ; i < 11 * 1024 ; i ++ {
buffer . WriteString ( fmt . Sprintf ( "[%05d] %s\n" , i , line ) )
}
putContent := buffer . String ( )
// Put object
buf := bytes . NewReader ( [ ] byte ( putContent ) )
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-11p/big-file-11" ,
int64 ( buf . Len ( ) ) , buf , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// Get object
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/test-bucket-11p/big-file-11" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
// This range spans into first two blocks.
request . Header . Add ( "Range" , "bytes=10485750-10485769" )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusPartialContent )
getContent , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
// Compare putContent and getContent
c . Assert ( string ( getContent ) , Equals , putContent [ 10485750 : 10485770 ] )
}
func ( s * MyAPISuite ) TestGetPartialObjectLarge10MiB ( c * C ) {
// Make bucket for this test.
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-10p" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
var buffer bytes . Buffer
line := "1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123"
// Create 10MiB content where each line contains 1024 characters.
for i := 0 ; i < 10 * 1024 ; i ++ {
buffer . WriteString ( fmt . Sprintf ( "[%05d] %s\n" , i , line ) )
}
putContent := buffer . String ( )
// Put object
buf := bytes . NewReader ( [ ] byte ( putContent ) )
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/test-bucket-10p/big-file-10" ,
int64 ( buf . Len ( ) ) , buf , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
// Get object
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/test-bucket-10p/big-file-10" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
c . Assert ( err , IsNil )
request . Header . Add ( "Range" , "bytes=2048-2058" )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusPartialContent )
getContent , err := ioutil . ReadAll ( response . Body )
c . Assert ( err , IsNil )
// Compare putContent and getContent
c . Assert ( string ( getContent ) , Equals , putContent [ 2048 : 2059 ] )
}
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
func ( s * MyAPISuite ) TestGetObjectErrors ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "GET" , s . testServer . Server . URL + "/getobjecterrors" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchBucket" , "The specified bucket does not exist." , http . StatusNotFound )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/getobjecterrors" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/getobjecterrors/bar" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "NoSuchKey" , "The specified key does not exist." , http . StatusNotFound )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/getobjecterrors-./bar" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "InvalidBucketName" , "The specified bucket is not valid." , http . StatusBadRequest )
}
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
func ( s * MyAPISuite ) TestGetObjectRangeErrors ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/getobjectrangeerrors" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 := bytes . NewReader ( [ ] byte ( "Hello World" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/getobjectrangeerrors/bar" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/getobjectrangeerrors/bar" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
request . Header . Add ( "Range" , "bytes=7-6" )
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
verifyError ( c , response , "InvalidRange" , "The requested range cannot be satisfied." , http . StatusRequestedRangeNotSatisfiable )
}
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
func ( s * MyAPISuite ) TestObjectMultipartAbort ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartabort" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/objectmultipartabort/object?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
decoder := xml . NewDecoder ( response . Body )
2015-09-19 03:52:01 -04:00
newResponse := & InitiateMultipartUploadResponse { }
2015-07-12 15:40:38 -04:00
err = decoder . Decode ( newResponse )
c . Assert ( err , IsNil )
c . Assert ( len ( newResponse . UploadID ) > 0 , Equals , true )
uploadID := newResponse . UploadID
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartabort/object?uploadId=" + uploadID + "&partNumber=1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response1 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response1 . StatusCode , Equals , http . StatusOK )
buffer2 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartabort/object?uploadId=" + uploadID + "&partNumber=2" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response2 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response2 . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "DELETE" , s . testServer . Server . URL + "/objectmultipartabort/object?uploadId=" + uploadID ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response3 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response3 . StatusCode , Equals , http . StatusNoContent )
}
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
func ( s * MyAPISuite ) TestBucketMultipartList ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/bucketmultipartlist" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/bucketmultipartlist/object?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
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 ( err , IsNil )
2015-07-12 15:40:38 -04:00
c . Assert ( response . StatusCode , Equals , http . StatusOK )
decoder := xml . NewDecoder ( response . Body )
2015-09-19 03:52:01 -04:00
newResponse := & InitiateMultipartUploadResponse { }
2015-07-12 15:40:38 -04:00
err = decoder . Decode ( newResponse )
c . Assert ( err , IsNil )
c . Assert ( len ( newResponse . UploadID ) > 0 , Equals , true )
uploadID := newResponse . UploadID
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/bucketmultipartlist/object?uploadId=" + uploadID + "&partNumber=1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response1 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response1 . StatusCode , Equals , http . StatusOK )
buffer2 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/bucketmultipartlist/object?uploadId=" + uploadID + "&partNumber=2" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response2 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response2 . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/bucketmultipartlist?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response3 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response3 . StatusCode , Equals , http . StatusOK )
2016-03-21 04:06:07 -04:00
// The reason to duplicate this structure here is to verify if the
// unmarshalling works from a client perspective, specifically
// while unmarshalling time.Time type for 'Initiated' field.
// time.Time does not honor xml marshaler, it means that we need
// to encode/format it before giving it to xml marshalling.
// This below check adds client side verification to see if its
// truly parseable.
2016-03-20 02:44:43 -04:00
// listMultipartUploadsResponse - format for list multipart uploads response.
type listMultipartUploadsResponse struct {
XMLName xml . Name ` xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult" json:"-" `
Bucket string
KeyMarker string
UploadIDMarker string ` xml:"UploadIdMarker" `
NextKeyMarker string
NextUploadIDMarker string ` xml:"NextUploadIdMarker" `
EncodingType string
MaxUploads int
IsTruncated bool
// All the in progress multipart uploads.
Uploads [ ] struct {
Key string
UploadID string ` xml:"UploadId" `
Initiator Initiator
Owner Owner
StorageClass string
Initiated time . Time // Keep this native to be able to parse properly.
}
Prefix string
Delimiter string
CommonPrefixes [ ] CommonPrefix
}
2015-07-12 15:40:38 -04:00
decoder = xml . NewDecoder ( response3 . Body )
2016-03-20 02:44:43 -04:00
newResponse3 := & listMultipartUploadsResponse { }
2015-07-12 15:40:38 -04:00
err = decoder . Decode ( newResponse3 )
c . Assert ( err , IsNil )
c . Assert ( newResponse3 . Bucket , Equals , "bucketmultipartlist" )
}
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
func ( s * MyAPISuite ) TestValidateObjectMultipartUploadID ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartlist-uploadid" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-01-26 17:57:46 -05:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/objectmultipartlist-uploadid/directory1/directory2/object?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-01-26 17:57:46 -05:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
2016-04-13 14:32:47 -04:00
c . Assert ( err , IsNil )
2016-01-26 17:57:46 -05:00
c . Assert ( response . StatusCode , Equals , http . StatusOK )
decoder := xml . NewDecoder ( response . Body )
newResponse := & InitiateMultipartUploadResponse { }
err = decoder . Decode ( newResponse )
c . Assert ( err , IsNil )
c . Assert ( len ( newResponse . UploadID ) > 0 , Equals , true )
}
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
func ( s * MyAPISuite ) TestObjectMultipartList ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartlist" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/objectmultipartlist/object?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
decoder := xml . NewDecoder ( response . Body )
2015-09-19 03:52:01 -04:00
newResponse := & InitiateMultipartUploadResponse { }
2015-07-12 15:40:38 -04:00
err = decoder . Decode ( newResponse )
c . Assert ( err , IsNil )
c . Assert ( len ( newResponse . UploadID ) > 0 , Equals , true )
uploadID := newResponse . UploadID
buffer1 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartlist/object?uploadId=" + uploadID + "&partNumber=1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response1 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response1 . StatusCode , Equals , http . StatusOK )
buffer2 := bytes . NewReader ( [ ] byte ( "hello world" ) )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultipartlist/object?uploadId=" + uploadID + "&partNumber=2" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response2 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response2 . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/objectmultipartlist/object?uploadId=" + uploadID ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
response3 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response3 . StatusCode , Equals , http . StatusOK )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "GET" , s . testServer . Server . URL + "/objectmultipartlist/object?max-parts=-2&uploadId=" + uploadID ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-16 20:32:33 -04:00
c . Assert ( err , IsNil )
response4 , err := client . Do ( request )
c . Assert ( err , IsNil )
2015-09-18 17:48:01 -04:00
verifyError ( c , response4 , "InvalidArgument" , "Argument maxParts must be an integer between 1 and 10000." , http . StatusBadRequest )
2015-07-12 15:40:38 -04:00
}
2016-05-11 19:13:37 -04:00
// Tests if valid md5 was set while uploading and server replies back
// with BadDigest.
func ( s * MyAPISuite ) TestObjectValidMD5 ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/object-valid-md5" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-11 19:13:37 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
// Create a byte array of 5MB.
data := bytes . Repeat ( [ ] byte ( "0123456789abcdef" ) , 5 * 1024 * 1024 / 16 )
hasher := md5 . New ( )
hasher . Write ( data )
md5Sum := hasher . Sum ( nil )
buffer1 := bytes . NewReader ( data )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/object-valid-md5/object" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-11 19:13:37 -04:00
c . Assert ( err , IsNil )
request . Header . Set ( "Content-Md5" , base64 . StdEncoding . EncodeToString ( md5Sum ) )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
buffer1 = bytes . NewReader ( data )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/object-valid-md5/object1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2016-05-11 19:13:37 -04:00
c . Assert ( err , IsNil )
request . Header . Set ( "Content-Md5" , "WvLTlMrX9NpYDQlEIFlnDw==" )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
2016-06-21 15:10:18 -04:00
verifyError ( c , response , "SignatureDoesNotMatch" , "The request signature we calculated does not match the signature you provided. Check your key and signing method." , http . StatusForbidden )
2016-05-11 19:13:37 -04:00
}
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
func ( s * MyAPISuite ) TestObjectMultipart ( c * C ) {
2016-06-21 15:10:18 -04:00
request , err := newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultiparts" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client := http . Client { }
response , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , 200 )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/objectmultiparts/object?uploads" ,
0 , nil , s . testServer . AccessKey , s . testServer . SecretKey )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
decoder := xml . NewDecoder ( response . Body )
2015-09-19 03:52:01 -04:00
newResponse := & InitiateMultipartUploadResponse { }
2015-07-12 15:40:38 -04:00
err = decoder . Decode ( newResponse )
c . Assert ( err , IsNil )
c . Assert ( len ( newResponse . UploadID ) > 0 , Equals , true )
uploadID := newResponse . UploadID
2016-05-09 02:49:49 -04:00
// Create a byte array of 5MB.
data := bytes . Repeat ( [ ] byte ( "0123456789abcdef" ) , 5 * 1024 * 1024 / 16 )
2016-02-05 23:05:56 -05:00
hasher := md5 . New ( )
2016-05-09 02:49:49 -04:00
hasher . Write ( data )
2016-02-05 23:05:56 -05:00
md5Sum := hasher . Sum ( nil )
2016-05-09 02:49:49 -04:00
buffer1 := bytes . NewReader ( data )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultiparts/object?uploadId=" + uploadID + "&partNumber=1" ,
int64 ( buffer1 . Len ( ) ) , buffer1 , s . testServer . AccessKey , s . testServer . SecretKey )
2016-03-05 19:43:48 -05:00
request . Header . Set ( "Content-Md5" , base64 . StdEncoding . EncodeToString ( md5Sum ) )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response1 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response1 . StatusCode , Equals , http . StatusOK )
2016-05-09 02:49:49 -04:00
// Byte array one 1 byte.
data = [ ] byte ( "0" )
hasher = md5 . New ( )
hasher . Write ( data )
md5Sum = hasher . Sum ( nil )
buffer2 := bytes . NewReader ( data )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "PUT" , s . testServer . Server . URL + "/objectmultiparts/object?uploadId=" + uploadID + "&partNumber=2" ,
int64 ( buffer2 . Len ( ) ) , buffer2 , s . testServer . AccessKey , s . testServer . SecretKey )
2016-03-05 19:43:48 -05:00
request . Header . Set ( "Content-Md5" , base64 . StdEncoding . EncodeToString ( md5Sum ) )
2015-07-12 15:40:38 -04:00
c . Assert ( err , IsNil )
client = http . Client { }
response2 , err := client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response2 . StatusCode , Equals , http . StatusOK )
2016-02-05 23:05:56 -05:00
// Complete multipart upload
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
completeUploads := & completeMultipartUpload {
Parts : [ ] completePart {
2015-07-12 15:40:38 -04:00
{
PartNumber : 1 ,
ETag : response1 . Header . Get ( "ETag" ) ,
} ,
{
PartNumber : 2 ,
ETag : response2 . Header . Get ( "ETag" ) ,
} ,
} ,
}
completeBytes , err := xml . Marshal ( completeUploads )
c . Assert ( err , IsNil )
2016-06-21 15:10:18 -04:00
request , err = newTestRequest ( "POST" , s . testServer . Server . URL + "/objectmultiparts/object?uploadId=" + uploadID ,
int64 ( len ( completeBytes ) ) , bytes . NewReader ( completeBytes ) , s . testServer . AccessKey , s . testServer . SecretKey )
2016-06-20 09:18:47 -04:00
c . Assert ( err , IsNil )
response , err = client . Do ( request )
c . Assert ( err , IsNil )
c . Assert ( response . StatusCode , Equals , http . StatusOK )
}