diff --git a/pkg/storage/donut/.gitignore b/pkg/donut/.gitignore similarity index 100% rename from pkg/storage/donut/.gitignore rename to pkg/donut/.gitignore diff --git a/pkg/storage/donut/LICENSE b/pkg/donut/LICENSE similarity index 100% rename from pkg/storage/donut/LICENSE rename to pkg/donut/LICENSE diff --git a/pkg/storage/donut/README.md b/pkg/donut/README.md similarity index 100% rename from pkg/storage/donut/README.md rename to pkg/donut/README.md diff --git a/pkg/storage/donut/bucket.go b/pkg/donut/bucket.go similarity index 100% rename from pkg/storage/donut/bucket.go rename to pkg/donut/bucket.go diff --git a/pkg/storage/donut/common.go b/pkg/donut/common.go similarity index 100% rename from pkg/storage/donut/common.go rename to pkg/donut/common.go diff --git a/pkg/storage/donut/config.go b/pkg/donut/config.go similarity index 100% rename from pkg/storage/donut/config.go rename to pkg/donut/config.go diff --git a/pkg/storage/donut/date.go b/pkg/donut/date.go similarity index 100% rename from pkg/storage/donut/date.go rename to pkg/donut/date.go diff --git a/pkg/storage/donut/definitions.go b/pkg/donut/definitions.go similarity index 100% rename from pkg/storage/donut/definitions.go rename to pkg/donut/definitions.go diff --git a/pkg/storage/donut/disk/disk.go b/pkg/donut/disk/disk.go similarity index 100% rename from pkg/storage/donut/disk/disk.go rename to pkg/donut/disk/disk.go diff --git a/pkg/storage/donut/disk/disk_darwin.go b/pkg/donut/disk/disk_darwin.go similarity index 100% rename from pkg/storage/donut/disk/disk_darwin.go rename to pkg/donut/disk/disk_darwin.go diff --git a/pkg/storage/donut/disk/disk_linux.go b/pkg/donut/disk/disk_linux.go similarity index 100% rename from pkg/storage/donut/disk/disk_linux.go rename to pkg/donut/disk/disk_linux.go diff --git a/pkg/donut/disk/disk_test.go b/pkg/donut/disk/disk_test.go new file mode 100644 index 000000000..18cb5145d --- /dev/null +++ b/pkg/donut/disk/disk_test.go @@ -0,0 +1,78 @@ +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 impliedisk. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package disk + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + . "github.com/minio/check" +) + +func TestDisk(t *testing.T) { TestingT(t) } + +type MyDiskSuite struct { + path string + disk Disk +} + +var _ = Suite(&MyDiskSuite{}) + +func (s *MyDiskSuite) SetUpSuite(c *C) { + path, err := ioutil.TempDir(os.TempDir(), "disk-") + c.Assert(err, IsNil) + s.path = path + d, err := New(s.path) + c.Assert(err, IsNil) + s.disk = d +} + +func (s *MyDiskSuite) TearDownSuite(c *C) { + os.RemoveAll(s.path) +} + +func (s *MyDiskSuite) TestDiskInfo(c *C) { + c.Assert(s.path, Equals, s.disk.GetPath()) + fsInfo := s.disk.GetFSInfo() + c.Assert(fsInfo["MountPoint"], Equals, s.disk.GetPath()) + c.Assert(fsInfo["FSType"], Not(Equals), "UNKNOWN") +} + +func (s *MyDiskSuite) TestDiskCreateDir(c *C) { + c.Assert(s.disk.MakeDir("hello"), IsNil) +} + +func (s *MyDiskSuite) TestDiskCreateFile(c *C) { + f, err := s.disk.CreateFile("hello1") + c.Assert(err, IsNil) + c.Assert(f.Name(), Equals, filepath.Join(s.path, "hello1")) + defer f.Close() +} + +func (s *MyDiskSuite) TestDiskOpenFile(c *C) { + f, err := s.disk.CreateFile("hello2") + c.Assert(err, IsNil) + c.Assert(f.Name(), Equals, filepath.Join(s.path, "hello2")) + defer f.Close() + + f, err = s.disk.OpenFile("hello2") + c.Assert(err, IsNil) + c.Assert(f.Name(), Equals, filepath.Join(s.path, "hello2")) + defer f.Close() +} diff --git a/pkg/donut/disk/errors.go b/pkg/donut/disk/errors.go new file mode 100644 index 000000000..5129665e9 --- /dev/null +++ b/pkg/donut/disk/errors.go @@ -0,0 +1,33 @@ +/* + * Minimalist Object Storage, (C) 2015 Minio, Inc. + * + * 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 impliedisk. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package disk + +// InvalidArgument invalid argument +type InvalidArgument struct{} + +func (e InvalidArgument) Error() string { + return "Invalid argument" +} + +// UnsupportedFilesystem unsupported filesystem type +type UnsupportedFilesystem struct { + Type string +} + +func (e UnsupportedFilesystem) Error() string { + return "Unsupported filesystem: " + e.Type +} diff --git a/pkg/storage/donut/donut-v1.go b/pkg/donut/donut-v1.go similarity index 100% rename from pkg/storage/donut/donut-v1.go rename to pkg/donut/donut-v1.go diff --git a/pkg/storage/donut/donut-v1_test.go b/pkg/donut/donut-v1_test.go similarity index 100% rename from pkg/storage/donut/donut-v1_test.go rename to pkg/donut/donut-v1_test.go diff --git a/pkg/storage/donut/donut-v2.go b/pkg/donut/donut-v2.go similarity index 99% rename from pkg/storage/donut/donut-v2.go rename to pkg/donut/donut-v2.go index 8cb9de52b..446596c89 100644 --- a/pkg/storage/donut/donut-v2.go +++ b/pkg/donut/donut-v2.go @@ -32,9 +32,9 @@ import ( "sync" "time" + "github.com/minio/minio/pkg/donut/trove" "github.com/minio/minio/pkg/iodine" "github.com/minio/minio/pkg/quick" - "github.com/minio/minio/pkg/storage/donut/trove" ) // total Number of buckets allowed @@ -397,9 +397,9 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s break } hash.Write(byteBuffer[0:length]) - donut.lock.Lock() + //donut.lock.Lock() ok := donut.objects.Append(objectKey, byteBuffer[0:length]) - donut.lock.Unlock() + //donut.lock.Unlock() if !ok { return ObjectMetadata{}, iodine.New(InternalError{}, nil) } @@ -431,10 +431,10 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s Size: int64(totalLength), } - donut.lock.Lock() + //donut.lock.Lock() storedBucket.objectMetadata[objectKey] = newObject donut.storedBuckets[bucket] = storedBucket - donut.lock.Unlock() + //donut.lock.Unlock() return newObject, nil } @@ -476,9 +476,9 @@ func (donut API) MakeBucket(bucketName, acl string) error { newBucket.bucketMetadata.Name = bucketName newBucket.bucketMetadata.Created = time.Now().UTC() newBucket.bucketMetadata.ACL = BucketACL(acl) - donut.lock.Lock() + //donut.lock.Lock() donut.storedBuckets[bucketName] = newBucket - donut.lock.Unlock() + //donut.lock.Unlock() return nil } diff --git a/pkg/storage/donut/donut-v2_test.go b/pkg/donut/donut-v2_test.go similarity index 100% rename from pkg/storage/donut/donut-v2_test.go rename to pkg/donut/donut-v2_test.go diff --git a/pkg/storage/donut/encoder.go b/pkg/donut/encoder.go similarity index 100% rename from pkg/storage/donut/encoder.go rename to pkg/donut/encoder.go diff --git a/pkg/storage/donut/errors.go b/pkg/donut/errors.go similarity index 100% rename from pkg/storage/donut/errors.go rename to pkg/donut/errors.go diff --git a/pkg/storage/donut/interfaces.go b/pkg/donut/interfaces.go similarity index 100% rename from pkg/storage/donut/interfaces.go rename to pkg/donut/interfaces.go diff --git a/pkg/storage/donut/management.go b/pkg/donut/management.go similarity index 98% rename from pkg/storage/donut/management.go rename to pkg/donut/management.go index c897524b2..3abbe45ca 100644 --- a/pkg/storage/donut/management.go +++ b/pkg/donut/management.go @@ -20,8 +20,8 @@ import ( "encoding/json" "path/filepath" + "github.com/minio/minio/pkg/donut/disk" "github.com/minio/minio/pkg/iodine" - "github.com/minio/minio/pkg/storage/donut/disk" ) // Heal - heal a donut and fix bad data blocks diff --git a/pkg/storage/donut/multipart.go b/pkg/donut/multipart.go similarity index 98% rename from pkg/storage/donut/multipart.go rename to pkg/donut/multipart.go index 1c76451c1..9946bcfce 100644 --- a/pkg/storage/donut/multipart.go +++ b/pkg/donut/multipart.go @@ -57,7 +57,7 @@ func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, er } donut.lock.RUnlock() - donut.lock.Lock() + //donut.lock.Lock() id := []byte(strconv.FormatInt(rand.Int63(), 10) + bucket + key + time.Now().String()) uploadIDSum := sha512.Sum512(id) uploadID := base64.URLEncoding.EncodeToString(uploadIDSum[:])[:47] @@ -67,7 +67,7 @@ func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, er initiated: time.Now(), totalParts: 0, } - donut.lock.Unlock() + //donut.lock.Unlock() return uploadID, nil } @@ -172,9 +172,9 @@ func (donut API) createObjectPart(bucket, key, uploadID string, partID int, cont md5SumBytes := hash.Sum(nil) totalLength := int64(len(readBytes)) - donut.lock.Lock() + //donut.lock.Lock() donut.multiPartObjects.Set(partKey, readBytes) - donut.lock.Unlock() + //donut.lock.Unlock() // setting up for de-allocation readBytes = nil @@ -192,20 +192,20 @@ func (donut API) createObjectPart(bucket, key, uploadID string, partID int, cont Size: totalLength, } - donut.lock.Lock() + //donut.lock.Lock() storedBucket.partMetadata[partKey] = newPart multiPartSession := storedBucket.multiPartSession[key] multiPartSession.totalParts++ storedBucket.multiPartSession[key] = multiPartSession donut.storedBuckets[bucket] = storedBucket - donut.lock.Unlock() + //donut.lock.Unlock() return md5Sum, nil } func (donut API) cleanupMultipartSession(bucket, key, uploadID string) { - donut.lock.Lock() - defer donut.lock.Unlock() + // donut.lock.Lock() + // defer donut.lock.Unlock() delete(donut.storedBuckets[bucket].multiPartSession, key) } @@ -237,7 +237,7 @@ func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, parts map } donut.lock.RUnlock() - donut.lock.Lock() + //donut.lock.Lock() var size int64 var fullObject bytes.Buffer for i := 1; i <= len(parts); i++ { @@ -264,7 +264,7 @@ func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, parts map object = nil go debug.FreeOSMemory() } - donut.lock.Unlock() + //donut.lock.Unlock() md5sumSlice := md5.Sum(fullObject.Bytes()) // this is needed for final verification inside CreateObject, do not convert this to hex diff --git a/pkg/storage/donut/node.go b/pkg/donut/node.go similarity index 97% rename from pkg/storage/donut/node.go rename to pkg/donut/node.go index a3f6d0231..3cab84667 100644 --- a/pkg/storage/donut/node.go +++ b/pkg/donut/node.go @@ -17,8 +17,8 @@ package donut import ( + "github.com/minio/minio/pkg/donut/disk" "github.com/minio/minio/pkg/iodine" - "github.com/minio/minio/pkg/storage/donut/disk" ) // node struct internal diff --git a/pkg/storage/donut/rebalance.go b/pkg/donut/rebalance.go similarity index 96% rename from pkg/storage/donut/rebalance.go rename to pkg/donut/rebalance.go index 7db4cfedd..d37ce1370 100644 --- a/pkg/storage/donut/rebalance.go +++ b/pkg/donut/rebalance.go @@ -21,8 +21,8 @@ import ( "os" "strings" + "github.com/minio/minio/pkg/donut/disk" "github.com/minio/minio/pkg/iodine" - "github.com/minio/minio/pkg/storage/donut/disk" ) // Rebalance - diff --git a/pkg/storage/donut/trove/trove.go b/pkg/donut/trove/trove.go similarity index 100% rename from pkg/storage/donut/trove/trove.go rename to pkg/donut/trove/trove.go diff --git a/pkg/storage/donut/trove/trove_test.go b/pkg/donut/trove/trove_test.go similarity index 100% rename from pkg/storage/donut/trove/trove_test.go rename to pkg/donut/trove/trove_test.go diff --git a/pkg/storage/donut/utils.go b/pkg/donut/utils.go similarity index 100% rename from pkg/storage/donut/utils.go rename to pkg/donut/utils.go diff --git a/pkg/server/api/api.go b/pkg/server/api/api.go index 8306e7c0b..3a9fdd217 100644 --- a/pkg/server/api/api.go +++ b/pkg/server/api/api.go @@ -16,7 +16,7 @@ package api -import "github.com/minio/minio/pkg/storage/donut" +import "github.com/minio/minio/pkg/donut" // Operation container for individual operations read by Ticket Master type Operation struct { diff --git a/pkg/server/api/bucket-handlers.go b/pkg/server/api/bucket-handlers.go index cbdc6b550..e47eabbc0 100644 --- a/pkg/server/api/bucket-handlers.go +++ b/pkg/server/api/bucket-handlers.go @@ -20,8 +20,8 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/minio/minio/pkg/donut" "github.com/minio/minio/pkg/iodine" - "github.com/minio/minio/pkg/storage/donut" "github.com/minio/minio/pkg/utils/log" ) @@ -83,6 +83,10 @@ func (api Minio) ListMultipartUploadsHandler(w http.ResponseWriter, req *http.Re } acceptsContentType := getContentType(req) + if !api.isValidOp(w, req, acceptsContentType) { + return + } + resources := getBucketMultipartResources(req.URL.Query()) if resources.MaxUploads == 0 { resources.MaxUploads = maxObjectList @@ -132,7 +136,6 @@ func (api Minio) ListObjectsHandler(w http.ResponseWriter, req *http.Request) { } acceptsContentType := getContentType(req) - // verify if bucket allows this operation if !api.isValidOp(w, req, acceptsContentType) { return } @@ -160,6 +163,10 @@ func (api Minio) ListObjectsHandler(w http.ResponseWriter, req *http.Request) { setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) + case donut.BucketNameInvalid: + writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) + case donut.BucketNotFound: + writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) case donut.ObjectNotFound: writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) case donut.ObjectNameInvalid: diff --git a/pkg/server/api/generic-handlers.go b/pkg/server/api/generic-handlers.go index 5d7f3fb00..08f36f94d 100644 --- a/pkg/server/api/generic-handlers.go +++ b/pkg/server/api/generic-handlers.go @@ -199,7 +199,7 @@ func getConfigFile() string { if err := os.MkdirAll(confPath, 0700); err != nil { return "" } - return filepath.Join(confPath, "config.json") + return filepath.Join(confPath, "users.json") } // validate auth header handler ServeHTTP() wrapper diff --git a/pkg/server/api/headers.go b/pkg/server/api/headers.go index 01f59b492..6d4cb81d3 100644 --- a/pkg/server/api/headers.go +++ b/pkg/server/api/headers.go @@ -23,7 +23,7 @@ import ( "net/http" "strconv" - "github.com/minio/minio/pkg/storage/donut" + "github.com/minio/minio/pkg/donut" ) // No encoder interface exists, so we create one. diff --git a/pkg/server/api/object-handlers.go b/pkg/server/api/object-handlers.go index e09dfe64c..210fe0fcc 100644 --- a/pkg/server/api/object-handlers.go +++ b/pkg/server/api/object-handlers.go @@ -24,8 +24,8 @@ import ( "encoding/xml" "github.com/gorilla/mux" + "github.com/minio/minio/pkg/donut" "github.com/minio/minio/pkg/iodine" - "github.com/minio/minio/pkg/storage/donut" "github.com/minio/minio/pkg/utils/log" ) @@ -48,8 +48,6 @@ func (api Minio) GetObjectHandler(w http.ResponseWriter, req *http.Request) { } acceptsContentType := getContentType(req) - - // verify if this operation is allowed if !api.isValidOp(w, req, acceptsContentType) { return } @@ -85,6 +83,10 @@ func (api Minio) GetObjectHandler(w http.ResponseWriter, req *http.Request) { } } } + case donut.BucketNameInvalid: + writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) + case donut.BucketNotFound: + writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) case donut.ObjectNotFound: writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) case donut.ObjectNameInvalid: @@ -109,8 +111,6 @@ func (api Minio) HeadObjectHandler(w http.ResponseWriter, req *http.Request) { } acceptsContentType := getContentType(req) - - // verify if this operation is allowed if !api.isValidOp(w, req, acceptsContentType) { return } @@ -125,6 +125,14 @@ func (api Minio) HeadObjectHandler(w http.ResponseWriter, req *http.Request) { case nil: setObjectHeaders(w, metadata) w.WriteHeader(http.StatusOK) + case donut.BucketNameInvalid: + error := getErrorCode(InvalidBucketName) + w.Header().Set("Server", "Minio") + w.WriteHeader(error.HTTPStatusCode) + case donut.BucketNotFound: + error := getErrorCode(NoSuchBucket) + w.Header().Set("Server", "Minio") + w.WriteHeader(error.HTTPStatusCode) case donut.ObjectNotFound: error := getErrorCode(NoSuchKey) w.Header().Set("Server", "Minio") @@ -155,7 +163,6 @@ func (api Minio) PutObjectHandler(w http.ResponseWriter, req *http.Request) { } acceptsContentType := getContentType(req) - // verify if this operation is allowed if !api.isValidOp(w, req, acceptsContentType) { return } @@ -203,6 +210,10 @@ func (api Minio) PutObjectHandler(w http.ResponseWriter, req *http.Request) { case nil: w.Header().Set("ETag", metadata.MD5Sum) writeSuccessResponse(w, acceptsContentType) + case donut.BucketNotFound: + writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) + case donut.BucketNameInvalid: + writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) case donut.ObjectExists: writeErrorResponse(w, req, MethodNotAllowed, acceptsContentType, req.URL.Path) case donut.BadDigest: @@ -231,8 +242,6 @@ func (api Minio) NewMultipartUploadHandler(w http.ResponseWriter, req *http.Requ } acceptsContentType := getContentType(req) - - // handle ACL's here at bucket level if !api.isValidOp(w, req, acceptsContentType) { return } @@ -278,8 +287,6 @@ func (api Minio) PutObjectPartHandler(w http.ResponseWriter, req *http.Request) } acceptsContentType := getContentType(req) - - // handle ACL's here at bucket level if !api.isValidOp(w, req, acceptsContentType) { return } @@ -355,8 +362,6 @@ func (api Minio) AbortMultipartUploadHandler(w http.ResponseWriter, req *http.Re } acceptsContentType := getContentType(req) - - // handle ACL's here at bucket level if !api.isValidOp(w, req, acceptsContentType) { return } @@ -392,8 +397,6 @@ func (api Minio) ListObjectPartsHandler(w http.ResponseWriter, req *http.Request } acceptsContentType := getContentType(req) - - // handle ACL's here at bucket level if !api.isValidOp(w, req, acceptsContentType) { return } @@ -438,8 +441,6 @@ func (api Minio) CompleteMultipartUploadHandler(w http.ResponseWriter, req *http } acceptsContentType := getContentType(req) - - // handle ACL's here at bucket level if !api.isValidOp(w, req, acceptsContentType) { return } diff --git a/pkg/server/api/resources.go b/pkg/server/api/resources.go index dea992b4e..8b26721dc 100644 --- a/pkg/server/api/resources.go +++ b/pkg/server/api/resources.go @@ -20,7 +20,7 @@ import ( "net/url" "strconv" - "github.com/minio/minio/pkg/storage/donut" + "github.com/minio/minio/pkg/donut" ) // parse bucket url queries diff --git a/pkg/server/api/response.go b/pkg/server/api/response.go index 5f6de4435..9d2a63f6e 100644 --- a/pkg/server/api/response.go +++ b/pkg/server/api/response.go @@ -20,7 +20,7 @@ import ( "net/http" "sort" - "github.com/minio/minio/pkg/storage/donut" + "github.com/minio/minio/pkg/donut" ) // Reply date format diff --git a/pkg/server/api_test.go b/pkg/server/api_test.go new file mode 100644 index 000000000..cecd07f5d --- /dev/null +++ b/pkg/server/api_test.go @@ -0,0 +1,948 @@ +/* + * Minimalist Object Storage, (C) 2014 Minio, Inc. + * + * 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. + */ + +package server + +import ( + "bytes" + "io" + "io/ioutil" + "strconv" + "strings" + "testing" + "time" + + "encoding/xml" + "net/http" + "net/http/httptest" + + . "github.com/minio/check" + "github.com/minio/minio/pkg/server/api" +) + +func Test(t *testing.T) { TestingT(t) } + +type MySuite struct{} + +var _ = Suite(&MySuite{}) + +var testServer *httptest.Server + +func (s *MySuite) SetUpSuite(c *C) { + httpHandler, minioAPI := getAPIHandler(api.Config{RateLimit: 16}) + go startTM(minioAPI) + testServer = httptest.NewServer(httpHandler) +} + +func (s *MySuite) TearDownSuite(c *C) { + testServer.Close() +} + +func setDummyAuthHeader(req *http.Request) { + authDummy := "AWS4-HMAC-SHA256 Credential=AC5NH40NQLTL4DUMMY/20130524/us-east-1/s3/aws4_request, SignedHeaders=date;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=98ad721746da40c64f1a55b78f14c238d841ea1380cd77a1b5971af0ece108bd" + req.Header.Set("Authorization", authDummy) + req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) +} + +func (s *MySuite) TestNonExistantBucket(c *C) { + request, err := http.NewRequest("HEAD", testServer.URL+"/nonexistantbucket", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusNotFound) +} + +func (s *MySuite) TestEmptyObject(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/emptyobject", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/emptyobject/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/emptyobject/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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())) +} + +func (s *MySuite) TestBucket(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/bucket", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("HEAD", testServer.URL+"/bucket", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +/* +func (s *MySuite) TestObject(c *C) { + buffer := bytes.NewBufferString("hello world") + request, err := http.NewRequest("PUT", testServer.URL+"/testobject", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/testobject/object", buffer) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/testobject/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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")) + +} +*/ + +func (s *MySuite) TestMultipleObjects(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/multipleobjects", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/multipleobjects/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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.NewBufferString("hello one") + request, err = http.NewRequest("PUT", testServer.URL+"/multipleobjects/object1", buffer1) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/multipleobjects/object1", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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.NewBufferString("hello two") + request, err = http.NewRequest("PUT", testServer.URL+"/multipleobjects/object2", buffer2) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/multipleobjects/object2", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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.NewBufferString("hello three") + request, err = http.NewRequest("PUT", testServer.URL+"/multipleobjects/object3", buffer3) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/multipleobjects/object3", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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"))) +} + +func (s *MySuite) TestNotImplemented(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/bucket/object?policy", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusNotImplemented) + +} + +func (s *MySuite) TestHeader(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/bucket/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + + verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound) +} + +func (s *MySuite) TestPutBucket(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/put-bucket", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +func (s *MySuite) TestPutObject(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/put-object", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/put-object/object", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +func (s *MySuite) TestListBuckets(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + _, err = readListBucket(response.Body) + c.Assert(err, IsNil) +} + +func readListBucket(reader io.Reader) (api.ListBucketsResponse, error) { + var results api.ListBucketsResponse + decoder := xml.NewDecoder(reader) + err := decoder.Decode(&results) + return results, err +} + +func (s *MySuite) TestNotBeAbleToCreateObjectInNonexistantBucket(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/innonexistantbucket/object", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "NoSuchBucket", "The specified bucket does not exist.", http.StatusNotFound) +} + +func (s *MySuite) TestHeadOnObject(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/headonobject", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/headonobject/object1", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("HEAD", testServer.URL+"/headonobject/object1", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +func (s *MySuite) TestHeadOnBucket(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/headonbucket", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("HEAD", testServer.URL+"/headonbucket", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +func (s *MySuite) TestDateFormat(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/dateformat", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + // set an invalid date + request.Header.Set("Date", "asfasdfadf") + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "RequestTimeTooSkewed", + "The difference between the request time and the server's time is too large.", http.StatusForbidden) + + request.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + setDummyAuthHeader(request) + response, err = client.Do(request) + c.Assert(response.StatusCode, Equals, http.StatusOK) +} + +func verifyHeaders(c *C, header http.Header, date time.Time, size int, contentType string, etag string) { + // Verify date + c.Assert(header.Get("Last-Modified"), Equals, date.Format(http.TimeFormat)) + + // verify size + c.Assert(header.Get("Content-Length"), Equals, strconv.Itoa(size)) + + // verify content type + c.Assert(header.Get("Content-Type"), Equals, contentType) + + // verify etag + c.Assert(header.Get("Etag"), Equals, "\""+etag+"\"") +} + +func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/", nil) + c.Assert(err, IsNil) + request.Header.Add("Accept", "application/json") + setDummyAuthHeader(request) + + 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) +} + +func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/xmlnamenotinobjectlistjson", nil) + c.Assert(err, IsNil) + request.Header.Add("Accept", "application/json") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/xmlnamenotinobjectlistjson", nil) + c.Assert(err, IsNil) + request.Header.Add("Accept", "application/json") + setDummyAuthHeader(request) + + 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) +} + +func (s *MySuite) TestContentTypePersists(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/contenttype-persists", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/contenttype-persists/one", bytes.NewBufferString("hello world")) + delete(request.Header, "Content-Type") + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("HEAD", testServer.URL+"/contenttype-persists/one", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream") + + request, err = http.NewRequest("GET", testServer.URL+"/contenttype-persists/one", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream") + + request, err = http.NewRequest("PUT", testServer.URL+"/contenttype-persists/two", bytes.NewBufferString("hello world")) + delete(request.Header, "Content-Type") + request.Header.Add("Content-Type", "application/json") + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("HEAD", testServer.URL+"/contenttype-persists/two", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream") + + request, err = http.NewRequest("GET", testServer.URL+"/contenttype-persists/two", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream") +} + +func (s *MySuite) TestPartialContent(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/partial-content", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/partial-content/bar", bytes.NewBufferString("Hello World")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + // prepare request + request, err = http.NewRequest("GET", testServer.URL+"/partial-content/bar", nil) + c.Assert(err, IsNil) + request.Header.Add("Accept", "application/json") + request.Header.Add("Range", "bytes=6-7") + setDummyAuthHeader(request) + + 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") +} + +func (s *MySuite) TestListObjectsHandlerErrors(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/objecthandlererrors-.", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest) + + request, err = http.NewRequest("GET", testServer.URL+"/objecthandlererrors", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "NoSuchBucket", "The specified bucket does not exist.", http.StatusNotFound) +} + +func (s *MySuite) TestPutBucketErrors(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/putbucket-.", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest) + + request, err = http.NewRequest("PUT", testServer.URL+"/putbucket", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/putbucket", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "private") + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "BucketAlreadyExists", "The requested bucket name is not available.", http.StatusConflict) + + request, err = http.NewRequest("PUT", testServer.URL+"/putbucket?acl", nil) + c.Assert(err, IsNil) + request.Header.Add("x-amz-acl", "unknown") + setDummyAuthHeader(request) + + 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) +} + +func (s *MySuite) TestGetObjectErrors(c *C) { + request, err := http.NewRequest("GET", testServer.URL+"/getobjecterrors", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "NoSuchBucket", "The specified bucket does not exist.", http.StatusNotFound) + + request, err = http.NewRequest("PUT", testServer.URL+"/getobjecterrors", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/getobjecterrors/bar", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound) + + request, err = http.NewRequest("GET", testServer.URL+"/getobjecterrors-./bar", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest) + +} + +func (s *MySuite) TestGetObjectRangeErrors(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/getobjectrangeerrors", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/getobjectrangeerrors/bar", bytes.NewBufferString("Hello World")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/getobjectrangeerrors/bar", nil) + request.Header.Add("Range", "bytes=7-6") + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + verifyError(c, response, "InvalidRange", "The requested range cannot be satisfied.", http.StatusRequestedRangeNotSatisfiable) +} + +func (s *MySuite) TestObjectMultipartAbort(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/objectmultipartabort", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, 200) + + request, err = http.NewRequest("POST", testServer.URL+"/objectmultipartabort/object?uploads", bytes.NewBufferString("")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + decoder := xml.NewDecoder(response.Body) + newResponse := &api.InitiateMultipartUploadResult{} + + err = decoder.Decode(newResponse) + c.Assert(err, IsNil) + c.Assert(len(newResponse.UploadID) > 0, Equals, true) + uploadID := newResponse.UploadID + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response1, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response1.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response2, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response2.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("DELETE", testServer.URL+"/objectmultipartabort/object?uploadId="+uploadID, nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response3, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response3.StatusCode, Equals, http.StatusNoContent) +} + +func (s *MySuite) TestBucketMultipartList(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/bucketmultipartlist", bytes.NewBufferString("")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, 200) + + request, err = http.NewRequest("POST", testServer.URL+"/bucketmultipartlist/object?uploads", bytes.NewBufferString("")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + decoder := xml.NewDecoder(response.Body) + newResponse := &api.InitiateMultipartUploadResult{} + + err = decoder.Decode(newResponse) + c.Assert(err, IsNil) + c.Assert(len(newResponse.UploadID) > 0, Equals, true) + uploadID := newResponse.UploadID + + request, err = http.NewRequest("PUT", testServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response1, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response1.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response2, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response2.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/bucketmultipartlist?uploads", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response3, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response3.StatusCode, Equals, http.StatusOK) + + decoder = xml.NewDecoder(response3.Body) + newResponse3 := &api.ListMultipartUploadsResponse{} + err = decoder.Decode(newResponse3) + c.Assert(err, IsNil) + c.Assert(newResponse3.Bucket, Equals, "bucketmultipartlist") +} + +func (s *MySuite) TestObjectMultipartList(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/objectmultipartlist", bytes.NewBufferString("")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, 200) + + request, err = http.NewRequest("POST", testServer.URL+"/objectmultipartlist/object?uploads", bytes.NewBufferString("")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + decoder := xml.NewDecoder(response.Body) + newResponse := &api.InitiateMultipartUploadResult{} + + err = decoder.Decode(newResponse) + c.Assert(err, IsNil) + c.Assert(len(newResponse.UploadID) > 0, Equals, true) + uploadID := newResponse.UploadID + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response1, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response1.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response2, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response2.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/objectmultipartlist/object?uploadId="+uploadID, nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response3, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response3.StatusCode, Equals, http.StatusOK) + +} + +func (s *MySuite) TestObjectMultipart(c *C) { + request, err := http.NewRequest("PUT", testServer.URL+"/objectmultiparts", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, 200) + + request, err = http.NewRequest("POST", testServer.URL+"/objectmultiparts/object?uploads", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + decoder := xml.NewDecoder(response.Body) + newResponse := &api.InitiateMultipartUploadResult{} + + err = decoder.Decode(newResponse) + c.Assert(err, IsNil) + c.Assert(len(newResponse.UploadID) > 0, Equals, true) + uploadID := newResponse.UploadID + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response1, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response1.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("PUT", testServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world")) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + client = http.Client{} + response2, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response2.StatusCode, Equals, http.StatusOK) + + // complete multipart upload + completeUploads := &api.CompleteMultipartUpload{ + Part: []api.Part{ + { + PartNumber: 1, + ETag: response1.Header.Get("ETag"), + }, + { + PartNumber: 2, + ETag: response2.Header.Get("ETag"), + }, + }, + } + + var completeBuffer bytes.Buffer + encoder := xml.NewEncoder(&completeBuffer) + encoder.Encode(completeUploads) + + request, err = http.NewRequest("POST", testServer.URL+"/objectmultiparts/object?uploadId="+uploadID, &completeBuffer) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + request, err = http.NewRequest("GET", testServer.URL+"/objectmultiparts/object", nil) + c.Assert(err, IsNil) + setDummyAuthHeader(request) + + 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 worldhello world")) +} + +func verifyError(c *C, response *http.Response, code, description string, statusCode int) { + data, err := ioutil.ReadAll(response.Body) + c.Assert(err, IsNil) + errorResponse := api.ErrorResponse{} + err = xml.Unmarshal(data, &errorResponse) + c.Assert(err, IsNil) + c.Assert(errorResponse.Code, Equals, code) + c.Assert(errorResponse.Message, Equals, description) + c.Assert(response.StatusCode, Equals, statusCode) +} diff --git a/pkg/storage/donut/disk/errors.go b/pkg/storage/donut/disk/errors.go deleted file mode 100644 index e195a8ded..000000000 --- a/pkg/storage/donut/disk/errors.go +++ /dev/null @@ -1,17 +0,0 @@ -package disk - -// InvalidArgument invalid argument -type InvalidArgument struct{} - -func (e InvalidArgument) Error() string { - return "Invalid argument" -} - -// UnsupportedFilesystem unsupported filesystem type -type UnsupportedFilesystem struct { - Type string -} - -func (e UnsupportedFilesystem) Error() string { - return "Unsupported filesystem: " + e.Type -}