You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
800 lines
29 KiB
800 lines
29 KiB
9 years ago
|
/*
|
||
9 years ago
|
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
||
9 years ago
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
8 years ago
|
package cmd
|
||
9 years ago
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/md5"
|
||
|
"encoding/hex"
|
||
9 years ago
|
"io"
|
||
9 years ago
|
"math/rand"
|
||
|
"strconv"
|
||
|
|
||
9 years ago
|
. "gopkg.in/check.v1"
|
||
9 years ago
|
)
|
||
|
|
||
9 years ago
|
// Return pointer to testOneByteReadEOF{}
|
||
|
func newTestReaderEOF(data []byte) io.Reader {
|
||
|
return &testOneByteReadEOF{false, data}
|
||
|
}
|
||
|
|
||
|
// OneByteReadEOF - implements io.Reader which returns 1 byte along with io.EOF error.
|
||
|
type testOneByteReadEOF struct {
|
||
|
eof bool
|
||
|
data []byte
|
||
|
}
|
||
|
|
||
|
func (r *testOneByteReadEOF) Read(p []byte) (n int, err error) {
|
||
|
if r.eof {
|
||
|
return 0, io.EOF
|
||
|
}
|
||
|
n = copy(p, r.data)
|
||
|
r.eof = true
|
||
|
return n, io.EOF
|
||
|
}
|
||
|
|
||
|
// Return pointer to testOneByteReadNoEOF{}
|
||
|
func newTestReaderNoEOF(data []byte) io.Reader {
|
||
|
return &testOneByteReadNoEOF{false, data}
|
||
|
}
|
||
|
|
||
|
// testOneByteReadNoEOF - implements io.Reader which returns 1 byte and nil error, but
|
||
|
// returns io.EOF on the next Read().
|
||
|
type testOneByteReadNoEOF struct {
|
||
|
eof bool
|
||
|
data []byte
|
||
|
}
|
||
|
|
||
|
func (r *testOneByteReadNoEOF) Read(p []byte) (n int, err error) {
|
||
|
if r.eof {
|
||
|
return 0, io.EOF
|
||
|
}
|
||
|
n = copy(p, r.data)
|
||
|
r.eof = true
|
||
|
return n, nil
|
||
|
}
|
||
|
|
||
9 years ago
|
type ObjectLayerAPISuite struct{}
|
||
|
|
||
|
var _ = Suite(&ObjectLayerAPISuite{})
|
||
|
|
||
|
// Wrapper for calling testMakeBucket for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestMakeBucket(c *C) {
|
||
|
ExecObjectLayerTest(c, testMakeBucket)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate bucket creation.
|
||
9 years ago
|
func testMakeBucket(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket-unknown")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testMultipartObjectCreation for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestMultipartObjectCreation(c *C) {
|
||
|
ExecObjectLayerTest(c, testMultipartObjectCreation)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate creation of part files during Multipart operation.
|
||
9 years ago
|
func testMultipartObjectCreation(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
uploadID, err := obj.NewMultipartUpload("bucket", "key", nil)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
// Create a byte array of 5MB.
|
||
|
data := bytes.Repeat([]byte("0123456789abcdef"), 5*1024*1024/16)
|
||
9 years ago
|
completedParts := completeMultipartUpload{}
|
||
9 years ago
|
for i := 1; i <= 10; i++ {
|
||
|
hasher := md5.New()
|
||
9 years ago
|
hasher.Write(data)
|
||
9 years ago
|
expectedMD5Sumhex := hex.EncodeToString(hasher.Sum(nil))
|
||
9 years ago
|
|
||
9 years ago
|
var calculatedMD5sum string
|
||
9 years ago
|
calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(data)), bytes.NewBuffer(data), expectedMD5Sumhex)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Errorf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if calculatedMD5sum != expectedMD5Sumhex {
|
||
|
c.Errorf("MD5 Mismatch")
|
||
|
}
|
||
9 years ago
|
completedParts.Parts = append(completedParts.Parts, completePart{PartNumber: i, ETag: calculatedMD5sum})
|
||
9 years ago
|
}
|
||
9 years ago
|
md5Sum, err := obj.CompleteMultipartUpload("bucket", "key", uploadID, completedParts.Parts)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if md5Sum != "7d364cb728ce42a74a96d22949beefb2-10" {
|
||
|
c.Errorf("Md5 mismtch")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testMultipartObjectAbort for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestMultipartObjectAbort(c *C) {
|
||
|
ExecObjectLayerTest(c, testMultipartObjectAbort)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate abortion of Multipart operation.
|
||
9 years ago
|
func testMultipartObjectAbort(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
uploadID, err := obj.NewMultipartUpload("bucket", "key", nil)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
|
parts := make(map[int]string)
|
||
9 years ago
|
metadata := make(map[string]string)
|
||
9 years ago
|
for i := 1; i <= 10; i++ {
|
||
|
randomPerm := rand.Perm(10)
|
||
|
randomString := ""
|
||
|
for _, num := range randomPerm {
|
||
|
randomString = randomString + strconv.Itoa(num)
|
||
|
}
|
||
|
|
||
|
hasher := md5.New()
|
||
|
hasher.Write([]byte(randomString))
|
||
9 years ago
|
expectedMD5Sumhex := hex.EncodeToString(hasher.Sum(nil))
|
||
9 years ago
|
|
||
9 years ago
|
metadata["md5"] = expectedMD5Sumhex
|
||
9 years ago
|
var calculatedMD5sum string
|
||
9 years ago
|
calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(randomString)), bytes.NewBufferString(randomString), expectedMD5Sumhex)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if calculatedMD5sum != expectedMD5Sumhex {
|
||
|
c.Errorf("Md5 Mismatch")
|
||
|
}
|
||
9 years ago
|
parts[i] = expectedMD5Sumhex
|
||
9 years ago
|
}
|
||
9 years ago
|
err = obj.AbortMultipartUpload("bucket", "key", uploadID)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testMultipleObjectCreation for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestMultipleObjectCreation(c *C) {
|
||
|
ExecObjectLayerTest(c, testMultipleObjectCreation)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate object creation.
|
||
9 years ago
|
func testMultipleObjectCreation(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
objects := make(map[string][]byte)
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
for i := 0; i < 10; i++ {
|
||
9 years ago
|
randomPerm := rand.Perm(100)
|
||
9 years ago
|
randomString := ""
|
||
|
for _, num := range randomPerm {
|
||
|
randomString = randomString + strconv.Itoa(num)
|
||
|
}
|
||
|
|
||
|
hasher := md5.New()
|
||
|
hasher.Write([]byte(randomString))
|
||
9 years ago
|
expectedMD5Sumhex := hex.EncodeToString(hasher.Sum(nil))
|
||
9 years ago
|
|
||
|
key := "obj" + strconv.Itoa(i)
|
||
|
objects[key] = []byte(randomString)
|
||
9 years ago
|
metadata := make(map[string]string)
|
||
|
metadata["md5Sum"] = expectedMD5Sumhex
|
||
9 years ago
|
var md5Sum string
|
||
|
md5Sum, err = obj.PutObject("bucket", key, int64(len(randomString)), bytes.NewBufferString(randomString), metadata)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if md5Sum != expectedMD5Sumhex {
|
||
|
c.Errorf("Md5 Mismatch")
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
|
for key, value := range objects {
|
||
|
var byteBuffer bytes.Buffer
|
||
9 years ago
|
err = obj.GetObject("bucket", key, 0, int64(len(value)), &byteBuffer)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if !bytes.Equal(byteBuffer.Bytes(), value) {
|
||
|
c.Errorf("%s: Mismatch of GetObject data with the expected one.", instanceType)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
objInfo, err := obj.GetObjectInfo("bucket", key)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if objInfo.Size != int64(len(value)) {
|
||
|
c.Errorf("%s: Size mismatch of the GetObject data.", instanceType)
|
||
|
}
|
||
|
|
||
9 years ago
|
}
|
||
|
}
|
||
|
|
||
9 years ago
|
// Wrapper for calling TestPaging for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestPaging(c *C) {
|
||
|
ExecObjectLayerTest(c, testPaging)
|
||
|
}
|
||
|
|
||
9 years ago
|
// Tests validate creation of objects and the order of listing using various filters for ListObjects operation.
|
||
9 years ago
|
func testPaging(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
obj.MakeBucket("bucket")
|
||
|
result, err := obj.ListObjects("bucket", "", "", "", 0)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(result.Objects) != 0 {
|
||
|
c.Errorf("%s: Number of objects in the result different from expected value.", instanceType)
|
||
|
}
|
||
|
if result.IsTruncated != false {
|
||
|
c.Errorf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated)
|
||
|
}
|
||
|
|
||
|
uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed."
|
||
9 years ago
|
// check before paging occurs.
|
||
9 years ago
|
for i := 0; i < 5; i++ {
|
||
|
key := "obj" + strconv.Itoa(i)
|
||
9 years ago
|
_, err = obj.PutObject("bucket", key, int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
|
result, err = obj.ListObjects("bucket", "", "", "", 5)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(result.Objects) != i+1 {
|
||
|
c.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, len(result.Objects), i+1)
|
||
|
}
|
||
|
if result.IsTruncated != false {
|
||
|
c.Errorf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated)
|
||
|
}
|
||
9 years ago
|
}
|
||
9 years ago
|
|
||
9 years ago
|
// check after paging occurs pages work.
|
||
9 years ago
|
for i := 6; i <= 10; i++ {
|
||
|
key := "obj" + strconv.Itoa(i)
|
||
9 years ago
|
_, err = obj.PutObject("bucket", key, int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "obj", "", "", 5)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(result.Objects) != 5 {
|
||
|
c.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, 5, len(result.Objects))
|
||
|
}
|
||
|
if result.IsTruncated != true {
|
||
|
c.Errorf("%s: Expected IsTruncated to be `true`, but instead found it to be `%v`", instanceType, result.IsTruncated)
|
||
|
}
|
||
9 years ago
|
}
|
||
9 years ago
|
// check paging with prefix at end returns less objects.
|
||
9 years ago
|
{
|
||
9 years ago
|
_, err = obj.PutObject("bucket", "newPrefix", int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
_, err = obj.PutObject("bucket", "newPrefix2", int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "new", "", "", 5)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(result.Objects) != 2 {
|
||
|
c.Errorf("%s: Expected length of objects to be %d, instead found to be %d", instanceType, 2, len(result.Objects))
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// check ordering of pages.
|
||
9 years ago
|
{
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "", "", "", 1000)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if result.Objects[0].Name != "newPrefix" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name)
|
||
|
}
|
||
|
if result.Objects[1].Name != "newPrefix2" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[1].Name)
|
||
|
}
|
||
|
if result.Objects[2].Name != "obj0" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[2].Name)
|
||
|
}
|
||
|
if result.Objects[3].Name != "obj1" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[3].Name)
|
||
|
}
|
||
|
if result.Objects[4].Name != "obj10" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[4].Name)
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// check delimited results with delimiter and prefix.
|
||
9 years ago
|
{
|
||
9 years ago
|
_, err = obj.PutObject("bucket", "this/is/delimited", int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
_, err = obj.PutObject("bucket", "this/is/also/a/delimited/file", int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "this/is/", "", "/", 10)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(result.Objects) != 1 {
|
||
|
c.Errorf("%s: Expected the number of objects in the result to be %d, but instead found %d", instanceType, 1, len(result.Objects))
|
||
|
}
|
||
|
if result.Prefixes[0] != "this/is/also/" {
|
||
|
c.Errorf("%s: Expected prefix to be `%s`, but instead found `%s`", instanceType, "this/is/also/", result.Prefixes[0])
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// check delimited results with delimiter without prefix.
|
||
9 years ago
|
{
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "", "", "/", 1000)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
|
||
|
if result.Objects[0].Name != "newPrefix" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name)
|
||
|
}
|
||
|
if result.Objects[1].Name != "newPrefix2" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[1].Name)
|
||
|
}
|
||
|
if result.Objects[2].Name != "obj0" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[2].Name)
|
||
|
}
|
||
|
if result.Objects[3].Name != "obj1" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[3].Name)
|
||
|
}
|
||
|
if result.Objects[4].Name != "obj10" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[4].Name)
|
||
|
}
|
||
|
if result.Prefixes[0] != "this/" {
|
||
|
c.Errorf("%s: Expected the prefix to be `%s`, but instead found `%s`", instanceType, "this/", result.Prefixes[0])
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// check results with Marker.
|
||
9 years ago
|
{
|
||
9 years ago
|
|
||
|
result, err = obj.ListObjects("bucket", "", "newPrefix", "", 3)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if result.Objects[0].Name != "newPrefix2" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix2", result.Objects[0].Name)
|
||
|
}
|
||
|
if result.Objects[1].Name != "obj0" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj0", result.Objects[1].Name)
|
||
|
}
|
||
|
if result.Objects[2].Name != "obj1" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj1", result.Objects[2].Name)
|
||
|
}
|
||
9 years ago
|
}
|
||
9 years ago
|
// check ordering of results with prefix.
|
||
9 years ago
|
{
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "obj", "", "", 1000)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if result.Objects[0].Name != "obj0" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj0", result.Objects[0].Name)
|
||
|
}
|
||
|
if result.Objects[1].Name != "obj1" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj1", result.Objects[1].Name)
|
||
|
}
|
||
|
if result.Objects[2].Name != "obj10" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj10", result.Objects[2].Name)
|
||
|
}
|
||
|
if result.Objects[3].Name != "obj2" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj2", result.Objects[3].Name)
|
||
|
}
|
||
|
if result.Objects[4].Name != "obj3" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "obj3", result.Objects[4].Name)
|
||
|
}
|
||
9 years ago
|
}
|
||
9 years ago
|
// check ordering of results with prefix and no paging.
|
||
9 years ago
|
{
|
||
9 years ago
|
result, err = obj.ListObjects("bucket", "new", "", "", 5)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if result.Objects[0].Name != "newPrefix" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix", result.Objects[0].Name)
|
||
|
}
|
||
|
if result.Objects[1].Name != "newPrefix2" {
|
||
|
c.Errorf("%s: Expected the object name to be `%s`, but instead found `%s`", instanceType, "newPrefix2", result.Objects[0].Name)
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
|
||
9 years ago
|
// Wrapper for calling testObjectOverwriteWorks for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestObjectOverwriteWorks(c *C) {
|
||
|
ExecObjectLayerTest(c, testObjectOverwriteWorks)
|
||
|
}
|
||
|
|
||
9 years ago
|
// Tests validate overwriting of an existing object.
|
||
9 years ago
|
func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
_, err = obj.PutObject("bucket", "object", int64(len("The list of parts was not in ascending order. The parts list must be specified in order by part number.")), bytes.NewBufferString("The list of parts was not in ascending order. The parts list must be specified in order by part number."), nil)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed."
|
||
|
length := int64(len(uploadContent))
|
||
|
_, err = obj.PutObject("bucket", "object", length, bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
|
var bytesBuffer bytes.Buffer
|
||
9 years ago
|
err = obj.GetObject("bucket", "object", 0, length, &bytesBuffer)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if string(bytesBuffer.Bytes()) != "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." {
|
||
|
c.Errorf("%s: Invalid upload ID error mismatch.", instanceType)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testNonExistantBucketOperations for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestNonExistantBucketOperations(c *C) {
|
||
|
ExecObjectLayerTest(c, testNonExistantBucketOperations)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate that bucket operation on non-existent bucket fails.
|
||
9 years ago
|
func testNonExistantBucketOperations(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
_, err := obj.PutObject("bucket1", "object", int64(len("one")), bytes.NewBufferString("one"), nil)
|
||
9 years ago
|
if err == nil {
|
||
|
c.Fatal("Expected error but found nil")
|
||
|
}
|
||
|
if err.Error() != "Bucket not found: bucket1" {
|
||
|
c.Errorf("%s: Expected the error msg to be `%s`, but instead found `%s`", instanceType, "Bucket not found: bucket1", err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testBucketRecreateFails for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestBucketRecreateFails(c *C) {
|
||
|
ExecObjectLayerTest(c, testBucketRecreateFails)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate that recreation of the bucket fails.
|
||
9 years ago
|
func testBucketRecreateFails(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("string")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
err = obj.MakeBucket("string")
|
||
9 years ago
|
if err == nil {
|
||
|
c.Fatalf("%s: Expected error but found nil.", instanceType)
|
||
|
}
|
||
|
|
||
|
if err.Error() != "Bucket exists: string" {
|
||
|
c.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, "Bucket exists: string", err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testPutObject for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestPutObject(c *C) {
|
||
|
ExecObjectLayerTest(c, testPutObject)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate PutObject without prefix.
|
||
9 years ago
|
func testPutObject(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
content := []byte("testcontent")
|
||
|
length := int64(len(content))
|
||
|
readerEOF := newTestReaderEOF(content)
|
||
|
readerNoEOF := newTestReaderNoEOF(content)
|
||
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
|
var bytesBuffer1 bytes.Buffer
|
||
|
_, err = obj.PutObject("bucket", "object", length, readerEOF, nil)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
err = obj.GetObject("bucket", "object", 0, length, &bytesBuffer1)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(bytesBuffer1.Bytes()) != len(content) {
|
||
|
c.Errorf("%s: Expected content length to be `%d`, but instead found `%d`", instanceType, len(content), len(bytesBuffer1.Bytes()))
|
||
|
}
|
||
9 years ago
|
|
||
|
var bytesBuffer2 bytes.Buffer
|
||
|
_, err = obj.PutObject("bucket", "object", length, readerNoEOF, nil)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
err = obj.GetObject("bucket", "object", 0, length, &bytesBuffer2)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(bytesBuffer2.Bytes()) != len(content) {
|
||
|
c.Errorf("%s: Expected content length to be `%d`, but instead found `%d`", instanceType, len(content), len(bytesBuffer2.Bytes()))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testPutObjectInSubdir for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestPutObjectInSubdir(c *C) {
|
||
|
ExecObjectLayerTest(c, testPutObjectInSubdir)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate PutObject with subdirectory prefix.
|
||
9 years ago
|
func testPutObjectInSubdir(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
uploadContent := `The specified multipart upload does not exist. The upload ID might be invalid, or the multipart
|
||
|
upload might have been aborted or completed.`
|
||
|
length := int64(len(uploadContent))
|
||
|
_, err = obj.PutObject("bucket", "dir1/dir2/object", length, bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
|
var bytesBuffer bytes.Buffer
|
||
9 years ago
|
err = obj.GetObject("bucket", "dir1/dir2/object", 0, length, &bytesBuffer)
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(bytesBuffer.Bytes()) != len(uploadContent) {
|
||
|
c.Errorf("%s: Expected length of downloaded data to be `%d`, but instead found `%d`",
|
||
|
instanceType, len(uploadContent), len(bytesBuffer.Bytes()))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testListBuckets for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestListBuckets(c *C) {
|
||
|
ExecObjectLayerTest(c, testListBuckets)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate ListBuckets.
|
||
9 years ago
|
func testListBuckets(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
// test empty list.
|
||
9 years ago
|
buckets, err := obj.ListBuckets()
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(buckets) != 0 {
|
||
|
c.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 0, len(buckets))
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
// add one and test exists.
|
||
9 years ago
|
err = obj.MakeBucket("bucket1")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
buckets, err = obj.ListBuckets()
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(buckets) != 1 {
|
||
|
c.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 1, len(buckets))
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
// add two and test exists.
|
||
9 years ago
|
err = obj.MakeBucket("bucket2")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
buckets, err = obj.ListBuckets()
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(buckets) != 2 {
|
||
|
c.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 2, len(buckets))
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
// add three and test exists + prefix.
|
||
9 years ago
|
err = obj.MakeBucket("bucket22")
|
||
9 years ago
|
|
||
9 years ago
|
buckets, err = obj.ListBuckets()
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(buckets) != 3 {
|
||
|
c.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 3, len(buckets))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testListBucketsOrder for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestListBucketsOrder(c *C) {
|
||
|
ExecObjectLayerTest(c, testListBucketsOrder)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate the order of result of ListBuckets.
|
||
9 years ago
|
func testListBucketsOrder(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
// if implementation contains a map, order of map keys will vary.
|
||
9 years ago
|
// this ensures they return in the same order each time.
|
||
9 years ago
|
// add one and test exists.
|
||
|
err := obj.MakeBucket("bucket1")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
err = obj.MakeBucket("bucket2")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
buckets, err := obj.ListBuckets()
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
if len(buckets) != 2 {
|
||
|
c.Errorf("%s: Expected number of bucket to be `%d`, but instead found `%d`", instanceType, 2, len(buckets))
|
||
|
}
|
||
|
|
||
|
if buckets[0].Name != "bucket1" {
|
||
|
c.Errorf("%s: Expected bucket name to be `%s`, but instead found `%s`", instanceType, "bucket1", buckets[0].Name)
|
||
|
}
|
||
|
if buckets[1].Name != "bucket2" {
|
||
|
c.Errorf("%s: Expected bucket name to be `%s`, but instead found `%s`", instanceType, "bucket2", buckets[1].Name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testListObjectsTestsForNonExistantBucket for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestListObjectsTestsForNonExistantBucket(c *C) {
|
||
|
ExecObjectLayerTest(c, testListObjectsTestsForNonExistantBucket)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate that ListObjects operation on a non-existent bucket fails as expected.
|
||
9 years ago
|
func testListObjectsTestsForNonExistantBucket(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
result, err := obj.ListObjects("bucket", "", "", "", 1000)
|
||
9 years ago
|
if err == nil {
|
||
|
c.Fatalf("%s: Expected error but found nil.", instanceType)
|
||
|
}
|
||
|
if len(result.Objects) != 0 {
|
||
|
c.Fatalf("%s: Expected number of objects in the result to be `%d`, but instead found `%d`", instanceType, 0, len(result.Objects))
|
||
|
}
|
||
|
if result.IsTruncated != false {
|
||
|
c.Fatalf("%s: Expected IsTruncated to be `false`, but instead found it to be `%v`", instanceType, result.IsTruncated)
|
||
|
}
|
||
|
if err.Error() != "Bucket not found: bucket" {
|
||
|
c.Errorf("%s: Expected the error msg to be `%s`, but instead found `%s`", instanceType, "Bucket not found: bucket", err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wrapper for calling testNonExistantObjectInBucket for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestNonExistantObjectInBucket(c *C) {
|
||
|
ExecObjectLayerTest(c, testNonExistantObjectInBucket)
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
// Tests validate that GetObject fails on a non-existent bucket as expected.
|
||
9 years ago
|
func testNonExistantObjectInBucket(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
_, err = obj.GetObjectInfo("bucket", "dir1")
|
||
9 years ago
|
if err == nil {
|
||
|
c.Fatalf("%s: Expected error but found nil", instanceType)
|
||
|
}
|
||
9 years ago
|
switch err := err.(type) {
|
||
9 years ago
|
case ObjectNotFound:
|
||
9 years ago
|
if err.Error() != "Object not found: bucket#dir1" {
|
||
|
c.Errorf("%s: Expected the Error message to be `%s`, but instead found `%s`", instanceType, "Object not found: bucket#dir1", err.Error())
|
||
|
}
|
||
9 years ago
|
default:
|
||
9 years ago
|
if err.Error() != "fails" {
|
||
|
c.Errorf("%s: Expected the Error message to be `%s`, but instead found it to be `%s`", instanceType, "fails", err.Error())
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
|
||
9 years ago
|
// Wrapper for calling testGetDirectoryReturnsObjectNotFound for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestGetDirectoryReturnsObjectNotFound(c *C) {
|
||
|
ExecObjectLayerTest(c, testGetDirectoryReturnsObjectNotFound)
|
||
|
}
|
||
|
|
||
9 years ago
|
// Tests validate that GetObject on an existing directory fails as expected.
|
||
9 years ago
|
func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
9 years ago
|
err := obj.MakeBucket("bucket")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
_, err = obj.PutObject("bucket", "dir1/dir3/object",
|
||
|
int64(len("The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.")),
|
||
|
bytes.NewBufferString("One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag."), nil)
|
||
|
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
_, err = obj.GetObjectInfo("bucket", "dir1")
|
||
9 years ago
|
switch err := err.(type) {
|
||
9 years ago
|
case ObjectNotFound:
|
||
9 years ago
|
if err.Bucket != "bucket" {
|
||
|
c.Errorf("%s: Expected the bucket name in the error message to be `%s`, but instead found `%s`", instanceType, "bucket", err.Bucket)
|
||
|
}
|
||
|
if err.Object != "dir1" {
|
||
|
c.Errorf("%s: Expected the object name in the error message to be `%s`, but instead found `%s`", instanceType, "dir1", err.Object)
|
||
|
}
|
||
9 years ago
|
default:
|
||
9 years ago
|
if err.Error() != "ObjectNotFound" {
|
||
|
c.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, "ObjectNotFound", err.Error())
|
||
|
}
|
||
9 years ago
|
}
|
||
|
|
||
9 years ago
|
_, err = obj.GetObjectInfo("bucket", "dir1/")
|
||
9 years ago
|
switch err := err.(type) {
|
||
9 years ago
|
case ObjectNameInvalid:
|
||
9 years ago
|
if err.Bucket != "bucket" {
|
||
|
c.Errorf("%s: Expected the bucket name in the error message to be `%s`, but instead found `%s`", instanceType, "bucket", err.Bucket)
|
||
|
}
|
||
|
if err.Object != "dir1/" {
|
||
|
c.Errorf("%s: Expected the object name in the error message to be `%s`, but instead found `%s`", instanceType, "dir1/", err.Object)
|
||
|
}
|
||
9 years ago
|
default:
|
||
9 years ago
|
// force a failure with a line number.
|
||
9 years ago
|
if err.Error() != "ObjectNotFound" {
|
||
|
c.Errorf("%s: Expected the error message to be `%s`, but instead found `%s`", instanceType, "ObjectNotFound", err.Error())
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
|
||
9 years ago
|
// Wrapper for calling testContentType for both XL and FS.
|
||
|
func (s *ObjectLayerAPISuite) TestContentType(c *C) {
|
||
|
ExecObjectLayerTest(c, testContentType)
|
||
|
}
|
||
9 years ago
|
|
||
9 years ago
|
// Test content-type.
|
||
|
func testContentType(obj ObjectLayer, instanceType string, c TestErrHandler) {
|
||
|
err := obj.MakeBucket("bucket")
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed."
|
||
9 years ago
|
// Test empty.
|
||
9 years ago
|
_, err = obj.PutObject("bucket", "minio.png", int64(len(uploadContent)), bytes.NewBufferString(uploadContent), nil)
|
||
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
9 years ago
|
objInfo, err := obj.GetObjectInfo("bucket", "minio.png")
|
||
9 years ago
|
if err != nil {
|
||
|
c.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||
|
}
|
||
|
|
||
|
if objInfo.ContentType != "image/png" {
|
||
|
c.Errorf("%s: Expected Content type to be `%s`, but instead found `%s`", instanceType, "image/png", objInfo.ContentType)
|
||
|
}
|
||
9 years ago
|
}
|