Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// +build ignore
/*
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
* Copyright 2015-2017 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 main
import (
"bytes"
"context"
"encoding/xml"
"errors"
"fmt"
"io"
"io/ioutil"
"math/rand"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"time"
"github.com/dustin/go-humanize"
jsoniter "github.com/json-iterator/go"
log "github.com/sirupsen/logrus"
"github.com/minio/minio-go/v6"
"github.com/minio/minio-go/v6/pkg/encrypt"
)
const letterBytes = "abcdefghijklmnopqrstuvwxyz01234569"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
const (
serverEndpoint = "SERVER_ENDPOINT"
accessKey = "ACCESS_KEY"
secretKey = "SECRET_KEY"
enableHTTPS = "ENABLE_HTTPS"
enableKMS = "ENABLE_KMS"
)
type mintJSONFormatter struct {
}
func (f *mintJSONFormatter) Format(entry *log.Entry) ([]byte, error) {
data := make(log.Fields, len(entry.Data))
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}
func cleanEmptyEntries(fields log.Fields) log.Fields {
cleanFields := log.Fields{}
for k, v := range fields {
if v != "" {
cleanFields[k] = v
}
}
return cleanFields
}
// log successful test runs
func successLogger(testName string, function string, args map[string]interface{}, startTime time.Time) *log.Entry {
// calculate the test case duration
duration := time.Since(startTime)
// log with the fields as per mint
fields := log.Fields{"name": "minio-go: " + testName, "function": function, "args": args, "duration": duration.Nanoseconds() / 1000000, "status": "PASS"}
return log.WithFields(cleanEmptyEntries(fields))
}
// As few of the features are not available in Gateway(s) currently, Check if err value is NotImplemented,
// and log as NA in that case and continue execution. Otherwise log as failure and return
func logError(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) {
// If server returns NotImplemented we assume it is gateway mode and hence log it as info and move on to next tests
// Special case for ComposeObject API as it is implemented on client side and adds specific error details like `Error in upload-part-copy` in
// addition to NotImplemented error returned from server
if isErrNotImplemented(err) {
ignoredLog(testName, function, args, startTime, message).Info()
} else {
failureLog(testName, function, args, startTime, alert, message, err).Fatal()
}
}
// log failed test runs
func failureLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) *log.Entry {
// calculate the test case duration
duration := time.Since(startTime)
var fields log.Fields
// log with the fields as per mint
if err != nil {
fields = log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
"duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message, "error": err}
} else {
fields = log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
"duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message}
}
return log.WithFields(cleanEmptyEntries(fields))
}
// log not applicable test runs
func ignoredLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string) *log.Entry {
// calculate the test case duration
duration := time.Since(startTime)
// log with the fields as per mint
fields := log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
"duration": duration.Nanoseconds() / 1000000, "status": "NA", "alert": alert}
return log.WithFields(cleanEmptyEntries(fields))
}
// Delete objects in given bucket, recursively
func cleanupBucket(bucketName string, c *minio.Client) error {
// Create a done channel to control 'ListObjectsV2' go routine.
doneCh := make(chan struct{})
// Exit cleanly upon return.
defer close(doneCh)
// Iterate over all objects in the bucket via listObjectsV2 and delete
for objCh := range c.ListObjectsV2(bucketName, "", true, doneCh) {
if objCh.Err != nil {
return objCh.Err
}
if objCh.Key != "" {
err := c.RemoveObject(bucketName, objCh.Key)
if err != nil {
return err
}
}
}
for objPartInfo := range c.ListIncompleteUploads(bucketName, "", true, doneCh) {
if objPartInfo.Err != nil {
return objPartInfo.Err
}
if objPartInfo.Key != "" {
err := c.RemoveIncompleteUpload(bucketName, objPartInfo.Key)
if err != nil {
return err
}
}
}
// objects are already deleted, clear the buckets now
err := c.RemoveBucket(bucketName)
if err != nil {
return err
}
return err
}
func cleanupVersionedBucket(bucketName string, c *minio.Client) error {
doneCh := make(chan struct{})
defer close(doneCh)
for obj := range c.ListObjectVersions(bucketName, "", true, doneCh) {
if obj.Err != nil {
return obj.Err
}
if obj.Key != "" {
err := c.RemoveObjectWithOptions(bucketName, obj.Key, minio.RemoveObjectOptions{VersionID: obj.VersionID})
if err != nil {
return err
}
}
}
for objPartInfo := range c.ListIncompleteUploads(bucketName, "", true, doneCh) {
if objPartInfo.Err != nil {
return objPartInfo.Err
}
if objPartInfo.Key != "" {
err := c.RemoveIncompleteUpload(bucketName, objPartInfo.Key)
if err != nil {
return err
}
}
}
// objects are already deleted, clear the buckets now
err := c.RemoveBucket(bucketName)
if err != nil {
return err
}
return err
}
func isErrNotImplemented(err error) bool {
return minio.ToErrorResponse(err).Code == "NotImplemented"
}
func init() {
// If server endpoint is not set, all tests default to
// using https://play.min.io
if os.Getenv(serverEndpoint) == "" {
os.Setenv(serverEndpoint, "play.min.io")
os.Setenv(accessKey, "Q3AM3UQ867SPQQA43P2F")
os.Setenv(secretKey, "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
os.Setenv(enableHTTPS, "1")
}
}
var mintDataDir = os.Getenv("MINT_DATA_DIR")
func getMintDataDirFilePath(filename string) (fp string) {
if mintDataDir == "" {
return
}
return filepath.Join(mintDataDir, filename)
}
type sizedReader struct {
io.Reader
size int
}
func (l *sizedReader) Size() int {
return l.size
}
func (l *sizedReader) Close() error {
return nil
}
type randomReader struct{ seed []byte }
func (r *randomReader) Read(b []byte) (int, error) {
return copy(b, bytes.Repeat(r.seed, len(b))), nil
}
// read data from file if it exists or optionally create a buffer of particular size
func getDataReader(fileName string) io.ReadCloser {
if mintDataDir == "" {
size := dataFileMap[fileName]
return &sizedReader{
Reader: io.LimitReader(&randomReader{
seed: []byte("a"),
}, int64(size)),
size: size,
}
}
reader, _ := os.Open(getMintDataDirFilePath(fileName))
return reader
}
// randString generates random names and prepends them with a known prefix.
func randString(n int, src rand.Source, prefix string) string {
b := make([]byte, n)
// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return prefix + string(b[0:30-len(prefix)])
}
var dataFileMap = map[string]int{
"datafile-1-b": 1,
"datafile-10-kB": 10 * humanize.KiByte,
"datafile-33-kB": 33 * humanize.KiByte,
"datafile-100-kB": 100 * humanize.KiByte,
"datafile-1.03-MB": 1056 * humanize.KiByte,
"datafile-1-MB": 1 * humanize.MiByte,
"datafile-5-MB": 5 * humanize.MiByte,
"datafile-6-MB": 6 * humanize.MiByte,
"datafile-11-MB": 11 * humanize.MiByte,
"datafile-129-MB": 129 * humanize.MiByte,
}
func isFullMode() bool {
return os.Getenv("MINT_MODE") == "full"
}
func getFuncName() string {
pc, _, _, _ := runtime.Caller(1)
return strings.TrimPrefix(runtime.FuncForPC(pc).Name(), "main.")
}
// Tests bucket re-create errors.
func testMakeBucketError() {
region := "eu-central-1"
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "MakeBucket(bucketName, region)"
// initialize logging params
args := map[string]interface{}{
"bucketName": "",
"region": region,
}
// skipping region functional tests for non s3 runs
if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
return
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket in 'eu-central-1'.
if err = c.MakeBucket(bucketName, region); err != nil {
logError(testName, function, args, startTime, "", "MakeBucket Failed", err)
return
}
if err = c.MakeBucket(bucketName, region); err == nil {
logError(testName, function, args, startTime, "", "Bucket already exists", err)
return
}
// Verify valid error response from server.
if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testMetadataSizeLimit() {
startTime := time.Now()
testName := getFuncName()
function := "PutObject(bucketName, objectName, reader, objectSize, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": "",
"opts.UserMetadata": "",
}
rand.Seed(startTime.Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
return
}
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
const HeaderSizeLimit = 8 * 1024
const UserMetadataLimit = 2 * 1024
// Meta-data greater than the 2 KB limit of AWS - PUT calls with this meta-data should fail
metadata := make(map[string]string)
metadata["X-Amz-Meta-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+UserMetadataLimit-len("X-Amz-Meta-Mint-Test")))
args["metadata"] = fmt.Sprint(metadata)
_, err = c.PutObject(bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
if err == nil {
logError(testName, function, args, startTime, "", "Created object with user-defined metadata exceeding metadata size limits", nil)
return
}
// Meta-data (headers) greater than the 8 KB limit of AWS - PUT calls with this meta-data should fail
metadata = make(map[string]string)
metadata["X-Amz-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+HeaderSizeLimit-len("X-Amz-Mint-Test")))
args["metadata"] = fmt.Sprint(metadata)
_, err = c.PutObject(bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
if err == nil {
logError(testName, function, args, startTime, "", "Created object with headers exceeding header size limits", nil)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Tests various bucket supported formats.
func testMakeBucketRegions() {
region := "eu-central-1"
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "MakeBucket(bucketName, region)"
// initialize logging params
args := map[string]interface{}{
"bucketName": "",
"region": region,
}
// skipping region functional tests for non s3 runs
if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
return
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket in 'eu-central-1'.
if err = c.MakeBucket(bucketName, region); err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
// Make a new bucket with '.' in its name, in 'us-west-2'. This
// request is internally staged into a path style instead of
// virtual host style.
region = "us-west-2"
args["region"] = region
if err = c.MakeBucket(bucketName+".withperiod", region); err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName+".withperiod", c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test PutObject using a large data to trigger multipart readat
func testPutObjectReadAt() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "PutObject(bucketName, objectName, reader, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": "",
"opts": "objectContentType",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
bufSize := dataFileMap["datafile-129-MB"]
var reader = getDataReader("datafile-129-MB")
defer reader.Close()
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
// Object content type
objectContentType := "binary/octet-stream"
args["objectContentType"] = objectContentType
n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: objectContentType})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
// Read the data back
r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "Get Object failed", err)
return
}
st, err := r.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "Stat Object failed", err)
return
}
if st.Size != int64(bufSize) {
logError(testName, function, args, startTime, "", fmt.Sprintf("Number of bytes in stat does not match, expected %d got %d", bufSize, st.Size), err)
return
}
if st.ContentType != objectContentType && st.ContentType != "application/octet-stream" {
logError(testName, function, args, startTime, "", "Content types don't match", err)
return
}
if err := r.Close(); err != nil {
logError(testName, function, args, startTime, "", "Object Close failed", err)
return
}
if err := r.Close(); err == nil {
logError(testName, function, args, startTime, "", "Object is already closed, didn't return error on Close", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testListObjectVersions() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "ListObjectVersions(bucketName, prefix, recursive)"
args := map[string]interface{}{
"bucketName": "",
"prefix": "",
"recursive": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
bufSize := dataFileMap["datafile-10-kB"]
var reader = getDataReader("datafile-10-kB")
n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
reader.Close()
bufSize = dataFileMap["datafile-1-b"]
reader = getDataReader("datafile-1-b")
n, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
reader.Close()
err = c.RemoveObject(bucketName, objectName)
if err != nil {
logError(testName, function, args, startTime, "", "Unexpected object deletion", err)
return
}
var deleteMarkers, versions int
doneCh := make(chan struct{})
objectsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
for info := range objectsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
if info.Key != objectName {
logError(testName, function, args, startTime, "", "Unexpected object name in listing objects", nil)
return
}
if info.VersionID == "" {
logError(testName, function, args, startTime, "", "Unexpected version id in listing objects", nil)
return
}
if info.IsDeleteMarker {
deleteMarkers++
if !info.IsLatest {
logError(testName, function, args, startTime, "", "Unexpected IsLatest field in listing objects", nil)
return
}
} else {
versions++
}
}
if deleteMarkers != 1 {
logError(testName, function, args, startTime, "", "Unexpected number of DeleteMarker elements in listing objects", nil)
return
}
if versions != 2 {
logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
return
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testStatObjectWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "StatObject"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
bufSize := dataFileMap["datafile-10-kB"]
var reader = getDataReader("datafile-10-kB")
n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
reader.Close()
bufSize = dataFileMap["datafile-1-b"]
reader = getDataReader("datafile-1-b")
n, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
reader.Close()
doneCh := make(chan struct{})
objectsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var results []minio.ObjectVersionInfo
for info := range objectsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
results = append(results, info)
}
if len(results) != 2 {
logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
return
}
for i := 0; i < len(results); i++ {
opts := minio.StatObjectOptions{minio.GetObjectOptions{VersionID: results[i].VersionID}}
statInfo, err := c.StatObject(bucketName, objectName, opts)
if err != nil {
logError(testName, function, args, startTime, "", "error during HEAD object", err)
return
}
if statInfo.ETag != results[i].ETag {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected ETag", err)
return
}
// We don't care about nano-second precision
if results[i].LastModified.Unix() != statInfo.LastModified.Unix() {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Last-Modified", err)
return
}
if statInfo.Size != results[i].Size {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Content-Length", err)
return
}
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testGetObjectWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "GetObject()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
// Save the contents of datafiles to check with GetObject() reader output later
var buffers [][]byte
var testFiles = []string{"datafile-1-b", "datafile-10-kB"}
for _, testFile := range testFiles {
r := getDataReader(testFile)
buf, err := ioutil.ReadAll(r)
if err != nil {
logError(testName, function, args, startTime, "", "unexpected failure", err)
return
}
r.Close()
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(len(buf)) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(len(buf))+" got "+string(n), err)
return
}
buffers = append(buffers, buf)
}
doneCh := make(chan struct{})
objectsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var results []minio.ObjectVersionInfo
for info := range objectsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
results = append(results, info)
}
if len(results) != 2 {
logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
return
}
sort.SliceStable(results, func(i, j int) bool {
return results[i].Size < results[j].Size
})
sort.SliceStable(buffers, func(i, j int) bool {
return len(buffers[i]) < len(buffers[j])
})
for i := 0; i < len(results); i++ {
opts := minio.GetObjectOptions{VersionID: results[i].VersionID}
reader, err := c.GetObject(bucketName, objectName, opts)
if err != nil {
logError(testName, function, args, startTime, "", "error during GET object", err)
return
}
statInfo, err := reader.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "error during calling reader.Stat()", err)
return
}
if statInfo.ETag != results[i].ETag {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected ETag", err)
return
}
// We don't care about nano-second precision
if results[i].LastModified.Unix() != statInfo.LastModified.Unix() {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Last-Modified", err)
return
}
if statInfo.Size != results[i].Size {
logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Content-Length", err)
return
}
tmpBuffer := bytes.NewBuffer([]byte{})
_, err = io.Copy(tmpBuffer, reader)
if err != nil {
logError(testName, function, args, startTime, "", "unexpected io.Copy()", err)
return
}
if !bytes.Equal(tmpBuffer.Bytes(), buffers[i]) {
fmt.Println(len(tmpBuffer.Bytes()), len(buffers[i]))
logError(testName, function, args, startTime, "", "unexpected content of GetObject()", err)
return
}
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testCopyObjectWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "CopyObject()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
var testFiles = []string{"datafile-1-b", "datafile-10-kB"}
for _, testFile := range testFiles {
r := getDataReader(testFile)
buf, err := ioutil.ReadAll(r)
if err != nil {
logError(testName, function, args, startTime, "", "unexpected failure", err)
return
}
r.Close()
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(len(buf)) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(len(buf))+" got "+string(n), err)
return
}
}
doneCh := make(chan struct{})
objectsVersionsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var infos []minio.ObjectVersionInfo
for info := range objectsVersionsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
infos = append(infos, info)
}
sort.Slice(infos, func(i, j int) bool {
return infos[i].Size < infos[j].Size
})
reader, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{VersionID: infos[0].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject of the oldest version content failed", err)
return
}
oldestContent, err := ioutil.ReadAll(reader)
if err != nil {
logError(testName, function, args, startTime, "", "Reading the oldest object version failed", err)
return
}
// Copy Source
src := minio.NewSourceInfo(bucketName, objectName, nil)
src.SetVersionID(infos[0].VersionID)
args["src"] = src
dst, err := minio.NewDestinationInfo(bucketName, objectName+"-copy", nil, nil)
args["dst"] = dst
if err != nil {
logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
return
}
// Perform the Copy
err = c.CopyObject(dst, src)
if err != nil {
logError(testName, function, args, startTime, "", "CopyObject failed", err)
return
}
// Destination object
readerCopy, err := c.GetObject(bucketName, objectName+"-copy", minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject failed", err)
return
}
defer readerCopy.Close()
newestContent, err := ioutil.ReadAll(readerCopy)
if err != nil {
logError(testName, function, args, startTime, "", "Reading from GetObject reader failed", err)
return
}
if len(newestContent) == 0 || !bytes.Equal(oldestContent, newestContent) {
logError(testName, function, args, startTime, "", "Unexpected destination object content", err)
return
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testComposeObjectWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "ComposeObject()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
// var testFiles = []string{"datafile-5-MB", "datafile-10-kB"}
var testFiles = []string{"datafile-5-MB", "datafile-10-kB"}
var testFilesBytes [][]byte
for _, testFile := range testFiles {
r := getDataReader(testFile)
buf, err := ioutil.ReadAll(r)
if err != nil {
logError(testName, function, args, startTime, "", "unexpected failure", err)
return
}
r.Close()
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(len(buf)) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(len(buf))+" got "+string(n), err)
return
}
testFilesBytes = append(testFilesBytes, buf)
}
doneCh := make(chan struct{})
objectsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var results []minio.ObjectVersionInfo
for info := range objectsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
results = append(results, info)
}
sort.SliceStable(results, func(i, j int) bool {
return results[i].Size > results[j].Size
})
// Source objects to concatenate. We also specify decryption
// key for each
src1 := minio.NewSourceInfo(bucketName, objectName, nil)
src1.SetVersionID(results[0].VersionID)
src2 := minio.NewSourceInfo(bucketName, objectName, nil)
src2.SetVersionID(results[1].VersionID)
// Create slice of sources.
srcs := []minio.SourceInfo{src1, src2}
// Create destination info
dst, err := minio.NewDestinationInfo(bucketName, objectName+"-copy", nil, nil)
if err != nil {
logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
return
}
err = c.ComposeObject(dst, srcs)
if err != nil {
logError(testName, function, args, startTime, "", "ComposeObject failed", err)
return
}
// Destination object
readerCopy, err := c.GetObject(bucketName, objectName+"-copy", minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject of the copy object failed", err)
return
}
defer readerCopy.Close()
copyContentBytes, err := ioutil.ReadAll(readerCopy)
if err != nil {
logError(testName, function, args, startTime, "", "Reading from the copy object reader failed", err)
return
}
var expectedContent []byte
for _, fileBytes := range testFilesBytes {
expectedContent = append(expectedContent, fileBytes...)
}
if len(copyContentBytes) == 0 || !bytes.Equal(copyContentBytes, expectedContent) {
logError(testName, function, args, startTime, "", "Unexpected destination object content", err)
return
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testRemoveObjectWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "DeleteObject()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
n, err := c.PutObject(bucketName, objectName, getDataReader("datafile-10-kB"), int64(dataFileMap["datafile-10-kB"]), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(dataFileMap["datafile-10-kB"]) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(dataFileMap["datafile-10-kB"])+" got "+string(n), err)
return
}
doneCh := make(chan struct{})
objectsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var version minio.ObjectVersionInfo
for info := range objectsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
version = info
break
}
err = c.RemoveObjectWithOptions(bucketName, objectName, minio.RemoveObjectOptions{VersionID: version.VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "DeleteObject failed", err)
return
}
doneCh = make(chan struct{})
objectsInfo = c.ListObjectVersions(bucketName, "", true, doneCh)
for range objectsInfo {
logError(testName, function, args, startTime, "", "Unexpected versioning info, should not have any one ", err)
return
}
err = c.RemoveBucket(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testRemoveObjectsWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "DeleteObjects()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
n, err := c.PutObject(bucketName, objectName, getDataReader("datafile-10-kB"), int64(dataFileMap["datafile-10-kB"]), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(dataFileMap["datafile-10-kB"]) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(dataFileMap["datafile-10-kB"])+" got "+string(n), err)
return
}
objectsVersions := make(chan minio.ObjectVersion)
go func() {
doneCh := make(chan struct{})
objectsVersionsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
for info := range objectsVersionsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
objectsVersions <- minio.ObjectVersion{
Key: info.Key,
VersionID: info.VersionID,
}
}
close(objectsVersions)
}()
removeErrors := c.RemoveObjectsWithVersions(context.Background(), bucketName, objectsVersions, minio.RemoveObjectsOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "DeleteObjects call failed", err)
return
}
for e := range removeErrors {
if e.Err != nil {
logError(testName, function, args, startTime, "", "Single delete operation failed", err)
return
}
}
doneCh := make(chan struct{})
objectsVersionsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
for range objectsVersionsInfo {
logError(testName, function, args, startTime, "", "Unexpected versioning info, should not have any one ", err)
return
}
err = c.RemoveBucket(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testObjectTaggingWithVersioning() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "{Get,Set,Remove}ObjectTagging()"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucketWithObjectLock(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
err = c.EnableVersioning(bucketName)
if err != nil {
logError(testName, function, args, startTime, "", "Enable versioning failed", err)
return
}
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
for _, file := range []string{"datafile-1-b", "datafile-10-kB"} {
n, err := c.PutObject(bucketName, objectName, getDataReader(file), int64(dataFileMap[file]), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(dataFileMap[file]) {
logError(testName, function, args, startTime, "",
"Number of bytes returned by PutObject does not match, expected "+string(dataFileMap[file])+" got "+string(n), err)
return
}
}
doneCh := make(chan struct{})
versionsInfo := c.ListObjectVersions(bucketName, "", true, doneCh)
var versions []minio.ObjectVersionInfo
for info := range versionsInfo {
if info.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
return
}
versions = append(versions, info)
}
sort.SliceStable(versions, func(i, j int) bool {
return versions[i].Size < versions[j].Size
})
tagsV1 := map[string]string{"key1": "val1"}
err = c.PutObjectTaggingWithOptions(context.Background(), bucketName, objectName, tagsV1, minio.PutObjectTaggingOptions{VersionID: versions[0].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "PutObjectTaggingWithOptions (1) failed", err)
return
}
tagsV2 := map[string]string{"key2": "val2"}
err = c.PutObjectTaggingWithOptions(context.Background(), bucketName, objectName, tagsV2, minio.PutObjectTaggingOptions{VersionID: versions[1].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "PutObjectTaggingWithOptions (2) failed", err)
return
}
type Tag struct {
Key string
Value string
}
type TagSet struct {
Tag []Tag
}
type GetObjectTaggingOutput struct {
TagSet TagSet
}
tagsEqual := func(tags map[string]string, getObjectTagging GetObjectTaggingOutput) bool {
for k, v := range tags {
found := false
for _, t := range getObjectTagging.TagSet.Tag {
if k+"="+v == t.Key+"="+t.Value {
found = true
break
}
}
if !found {
return false
}
}
return true
}
tagsV1XML, err := c.GetObjectTaggingWithOptions(context.Background(), bucketName, objectName, minio.GetObjectTaggingOptions{VersionID: versions[0].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "GetObjectTaggingWithOptions failed", err)
return
}
var getObjectTaggingV1 GetObjectTaggingOutput
err = xml.Unmarshal([]byte(tagsV1XML), &getObjectTaggingV1)
if err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during XML unmarshal (1)", err)
return
}
if !tagsEqual(tagsV1, getObjectTaggingV1) {
logError(testName, function, args, startTime, "", "Unexpected tags content (1)", err)
return
}
tagsV2XML, err := c.GetObjectTaggingWithContext(context.Background(), bucketName, objectName)
if err != nil {
logError(testName, function, args, startTime, "", "GetObjectTaggingWithContext failed", err)
return
}
var getObjectTaggingV2 GetObjectTaggingOutput
err = xml.Unmarshal([]byte(tagsV2XML), &getObjectTaggingV2)
if err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during XML unmarshal (2)", err)
return
}
if !tagsEqual(tagsV2, getObjectTaggingV2) {
logError(testName, function, args, startTime, "", "Unexpected tags content (2)", err)
return
}
err = c.RemoveObjectTaggingWithOptions(context.Background(), bucketName, objectName, minio.RemoveObjectTaggingOptions{VersionID: versions[0].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "PutObjectTaggingWithOptions (2) failed", err)
return
}
emptyTagsXML, err := c.GetObjectTaggingWithOptions(context.Background(), bucketName, objectName,
minio.GetObjectTaggingOptions{VersionID: versions[0].VersionID})
if err != nil {
logError(testName, function, args, startTime, "", "GetObjectTaggingWithOptions failed", err)
return
}
var getObjectExpectedEmptyTagging GetObjectTaggingOutput
err = xml.Unmarshal([]byte(emptyTagsXML), &getObjectExpectedEmptyTagging)
if err != nil {
logError(testName, function, args, startTime, "", "Unexpected error during XML unmarshal (3)", err)
return
}
if len(getObjectExpectedEmptyTagging.TagSet.Tag) != 0 {
logError(testName, function, args, startTime, "", "Unexpected tags content (2)", err)
return
}
// Delete all objects and their versions as long as the bucket itself
if err = cleanupVersionedBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test PutObject using a large data to trigger multipart readat
func testPutObjectWithMetadata() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "PutObject(bucketName, objectName, reader,size, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": "",
"opts": "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
}
if !isFullMode() {
ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
return
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "Make bucket failed", err)
return
}
bufSize := dataFileMap["datafile-129-MB"]
var reader = getDataReader("datafile-129-MB")
defer reader.Close()
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
// Object custom metadata
customContentType := "custom/contenttype"
args["metadata"] = map[string][]string{
"Content-Type": {customContentType},
"X-Amz-Meta-CustomKey": {"extra spaces in value"},
}
n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{
ContentType: customContentType})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
return
}
// Read the data back
r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject failed", err)
return
}
st, err := r.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "Stat failed", err)
return
}
if st.Size != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
return
}
if st.ContentType != customContentType && st.ContentType != "application/octet-stream" {
logError(testName, function, args, startTime, "", "ContentType does not match, expected "+customContentType+" got "+st.ContentType, err)
return
}
if err := r.Close(); err != nil {
logError(testName, function, args, startTime, "", "Object Close failed", err)
return
}
if err := r.Close(); err == nil {
logError(testName, function, args, startTime, "", "Object already closed, should respond with error", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
func testPutObjectWithContentLanguage() {
// initialize logging params
objectName := "test-object"
startTime := time.Now()
testName := getFuncName()
function := "PutObject(bucketName, objectName, reader, size, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": objectName,
"size": -1,
"opts": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.NewV4(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
data := bytes.Repeat([]byte("a"), int(0))
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(data), int64(0), minio.PutObjectOptions{
ContentLanguage: "en",
})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != 0 {
logError(testName, function, args, startTime, "", "Expected upload object '0' doesn't match with PutObject return value", err)
return
}
objInfo, err := c.StatObject(bucketName, objectName, minio.StatObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "StatObject failed", err)
return
}
if objInfo.Metadata.Get("Content-Language") != "en" {
logError(testName, function, args, startTime, "", "Expected content-language 'en' doesn't match with StatObject return value", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test put object with streaming signature.
func testPutObjectStreaming() {
// initialize logging params
objectName := "test-object"
startTime := time.Now()
testName := getFuncName()
function := "PutObject(bucketName, objectName, reader,size,opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": objectName,
"size": -1,
"opts": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.NewV4(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Upload an object.
sizes := []int64{0, 64*1024 - 1, 64 * 1024}
for _, size := range sizes {
data := bytes.Repeat([]byte("a"), int(size))
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(data), int64(size), minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "PutObjectStreaming failed", err)
return
}
if n != size {
logError(testName, function, args, startTime, "", "Expected upload object size doesn't match with PutObjectStreaming return value", err)
return
}
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test get object seeker from the end, using whence set to '2'.
func testGetObjectSeekEnd() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "GetObject(bucketName, objectName)"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Generate 33K of data.
bufSize := dataFileMap["datafile-33-kB"]
var reader = getDataReader("datafile-33-kB")
defer reader.Close()
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
buf, err := ioutil.ReadAll(reader)
if err != nil {
logError(testName, function, args, startTime, "", "ReadAll failed", err)
return
}
n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes read does not match, expected "+string(int64(bufSize))+" got "+string(n), err)
return
}
// Read the data back
r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject failed", err)
return
}
st, err := r.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "Stat failed", err)
return
}
if st.Size != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes read does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
return
}
pos, err := r.Seek(-100, 2)
if err != nil {
logError(testName, function, args, startTime, "", "Object Seek failed", err)
return
}
if pos != st.Size-100 {
logError(testName, function, args, startTime, "", "Incorrect position", err)
return
}
buf2 := make([]byte, 100)
m, err := io.ReadFull(r, buf2)
if err != nil {
logError(testName, function, args, startTime, "", "Error reading through io.ReadFull", err)
return
}
if m != len(buf2) {
logError(testName, function, args, startTime, "", "Number of bytes dont match, expected "+string(len(buf2))+" got "+string(m), err)
return
}
hexBuf1 := fmt.Sprintf("%02x", buf[len(buf)-100:])
hexBuf2 := fmt.Sprintf("%02x", buf2[:m])
if hexBuf1 != hexBuf2 {
logError(testName, function, args, startTime, "", "Values at same index dont match", err)
return
}
pos, err = r.Seek(-100, 2)
if err != nil {
logError(testName, function, args, startTime, "", "Object Seek failed", err)
return
}
if pos != st.Size-100 {
logError(testName, function, args, startTime, "", "Incorrect position", err)
return
}
if err = r.Close(); err != nil {
logError(testName, function, args, startTime, "", "ObjectClose failed", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test get object reader to not throw error on being closed twice.
func testGetObjectClosedTwice() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "GetObject(bucketName, objectName)"
args := map[string]interface{}{}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Generate 33K of data.
bufSize := dataFileMap["datafile-33-kB"]
var reader = getDataReader("datafile-33-kB")
defer reader.Close()
// Save the data
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args["objectName"] = objectName
n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
if n != int64(bufSize) {
logError(testName, function, args, startTime, "", "PutObject response doesn't match sent bytes, expected "+string(int64(bufSize))+" got "+string(n), err)
return
}
// Read the data back
r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject failed", err)
return
}
st, err := r.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "Stat failed", err)
return
}
if st.Size != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
return
}
if err := r.Close(); err != nil {
logError(testName, function, args, startTime, "", "Object Close failed", err)
return
}
if err := r.Close(); err == nil {
logError(testName, function, args, startTime, "", "Already closed object. No error returned", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test RemoveObjectsWithContext request context cancels after timeout
func testRemoveObjectsWithContext() {
// Initialize logging params.
startTime := time.Now()
testName := getFuncName()
function := "RemoveObjectsWithContext(ctx, bucketName, objectsCh)"
args := map[string]interface{}{
"bucketName": "",
}
// Seed random based on current tie.
rand.Seed(time.Now().Unix())
// Instantiate new minio client.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Enable tracing, write to stdout.
// c.TraceOn(os.Stderr)
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
}
// Generate put data.
r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
// Multi remove of 20 objects.
nrObjects := 20
objectsCh := make(chan string)
go func() {
defer close(objectsCh)
for i := 0; i < nrObjects; i++ {
objectName := "sample" + strconv.Itoa(i) + ".txt"
_, err = c.PutObject(bucketName, objectName, r, 8, minio.PutObjectOptions{ContentType: "application/octet-stream"})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
continue
}
objectsCh <- objectName
}
}()
// Set context to cancel in 1 nanosecond.
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
args["ctx"] = ctx
defer cancel()
// Call RemoveObjectsWithContext API with short timeout.
errorCh := c.RemoveObjectsWithContext(ctx, bucketName, objectsCh)
// Check for error.
select {
case r := <-errorCh:
if r.Err == nil {
logError(testName, function, args, startTime, "", "RemoveObjectsWithContext should fail on short timeout", err)
return
}
}
// Set context with longer timeout.
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
args["ctx"] = ctx
defer cancel()
// Perform RemoveObjectsWithContext with the longer timeout. Expect the removals to succeed.
errorCh = c.RemoveObjectsWithContext(ctx, bucketName, objectsCh)
select {
case r, more := <-errorCh:
if more || r.Err != nil {
logError(testName, function, args, startTime, "", "Unexpected error", r.Err)
return
}
}
// Delete all objects and buckets.
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Test removing multiple objects with Remove API
func testRemoveMultipleObjects() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "RemoveObjects(bucketName, objectsCh)"
args := map[string]interface{}{
"bucketName": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Enable tracing, write to stdout.
// c.TraceOn(os.Stderr)
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
// Multi remove of 1100 objects
nrObjects := 200
objectsCh := make(chan string)
go func() {
defer close(objectsCh)
// Upload objects and send them to objectsCh
for i := 0; i < nrObjects; i++ {
objectName := "sample" + strconv.Itoa(i) + ".txt"
_, err = c.PutObject(bucketName, objectName, r, 8, minio.PutObjectOptions{ContentType: "application/octet-stream"})
if err != nil {
logError(testName, function, args, startTime, "", "PutObject failed", err)
continue
}
objectsCh <- objectName
}
}()
// Call RemoveObjects API
errorCh := c.RemoveObjects(bucketName, objectsCh)
// Check if errorCh doesn't receive any error
select {
case r, more := <-errorCh:
if more {
logError(testName, function, args, startTime, "", "Unexpected error", r.Err)
return
}
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Tests FPutObject of a big file to trigger multipart
func testFPutObjectMultipart() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "FPutObject(bucketName, objectName, fileName, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": "",
"fileName": "",
"opts": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
args["bucketName"] = bucketName
// Make a new bucket.
err = c.MakeBucket(bucketName, "us-east-1")
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Upload 4 parts to utilize all 3 'workers' in multipart and still have a part to upload.
var fileName = getMintDataDirFilePath("datafile-129-MB")
if fileName == "" {
// Make a temp file with minPartSize bytes of data.
file, err := ioutil.TempFile(os.TempDir(), "FPutObjectTest")
if err != nil {
logError(testName, function, args, startTime, "", "TempFile creation failed", err)
return
}
// Upload 2 parts to utilize all 3 'workers' in multipart and still have a part to upload.
if _, err = io.Copy(file, getDataReader("datafile-129-MB")); err != nil {
logError(testName, function, args, startTime, "", "Copy failed", err)
return
}
if err = file.Close(); err != nil {
logError(testName, function, args, startTime, "", "File Close failed", err)
return
}
fileName = file.Name()
args["fileName"] = fileName
}
totalSize := dataFileMap["datafile-129-MB"]
// Set base object name
objectName := bucketName + "FPutObject" + "-standard"
args["objectName"] = objectName
objectContentType := "testapplication/octet-stream"
args["objectContentType"] = objectContentType
// Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
n, err := c.FPutObject(bucketName, objectName, fileName, minio.PutObjectOptions{ContentType: objectContentType})
if err != nil {
logError(testName, function, args, startTime, "", "FPutObject failed", err)
return
}
if n != int64(totalSize) {
logError(testName, function, args, startTime, "", "FPutObject failed", err)
return
}
r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "GetObject failed", err)
return
}
objInfo, err := r.Stat()
if err != nil {
logError(testName, function, args, startTime, "", "Unexpected error", err)
return
}
if objInfo.Size != int64(totalSize) {
logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(totalSize))+" got "+string(objInfo.Size), err)
return
}
if objInfo.ContentType != objectContentType && objInfo.ContentType != "application/octet-stream" {
logError(testName, function, args, startTime, "", "ContentType doesn't match", err)
return
}
// Delete all objects and buckets
if err = cleanupBucket(bucketName, c); err != nil {
logError(testName, function, args, startTime, "", "Cleanup failed", err)
return
}
successLogger(testName, function, args, startTime).Info()
}
// Tests FPutObject with null contentType (default = application/octet-stream)
func testFPutObject() {
// initialize logging params
startTime := time.Now()
testName := getFuncName()
function := "FPutObject(bucketName, objectName, fileName, opts)"
args := map[string]interface{}{
"bucketName": "",
"objectName": "",
"fileName": "",
"opts": "",
}
// Seed random based on current time.
rand.Seed(time.Now().Unix())
// Instantiate new minio client object.
c, err := minio.New(
os.Getenv(serverEndpoint),
os.Getenv(accessKey),
os.Getenv(secretKey),
mustParseBool(os.Getenv(enableHTTPS)),
)
if err != nil {
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
return
}
// Enable tracing, write to stderr.
// c.TraceOn(os.Stderr)
// Set user agent.
c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
// Generate a new random bucket name.
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
location := "us-east-1"
// Make a new bucket.
args["bucketName"] = bucketName
args["location"] = location
function = "MakeBucket()bucketName, location"
err = c.MakeBucket(bucketName, location)
if err != nil {
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
return
}
// Upload 3 parts worth of data to use all 3 of multiparts 'workers' and have an extra part.
// Use different data in part for multipart tests to check parts are uploaded in correct order.
var fName = getMintDataDirFilePath("datafile-129-MB")
if fName == "" {
// Make a temp file with minPartSize bytes of data.
file, err := ioutil.TempFile(os.TempDir(), "FPutObjectTest")
if err != nil {
logError(testName, function, args, startTime, "", "TempFile creation failed", err)
return
}
// Upload 3 parts to utilize all 3 'workers' in multipart and still have a part to upload.
if _, err = io.Copy(file, getDataReader("datafile-129-MB")); err != nil {
logError(testName, function, args, startTime, "", "File copy failed", err)
return
}
// Close the file pro-actively for windows.
if err = file.Close(); err != nil {
logError(testName, function, args, startTime, "", "File close failed", err)
return
}
defer os.Remove(file.Name())
fName = file.Name()
}
totalSize := dataFileMap["datafile-129-MB"]
// Set base object name
function = "FPutObject(bucketName, objectName, fileName, opts)"
objectName := bucketName + "FPutObject"
args["objectName"] = objectName + "-standard"
args["fileName"] = fName
args["opts"] = minio.PutObjectOptions{ContentType: "application/octet-stream"}
// Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
n, err := c.FPutObject(bucketName, objectName+"-standard", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
if err != nil {
logError(testName, function, args, startTime, "", "FPutObject failed", err)
return
}
if n != int64(totalSize) {
logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
return
}
// Perform FPutObject with no contentType provided (Expecting application/octet-stream)
args["objectName"] = objectName + "-Octet"
n, err = c.FPutObject(bucketName, objectName+"-Octet", fName, minio.PutObjectOptions{})
if err != nil {
logError(testName, function, args, startTime, "", "File close failed", err)
return
}
if n != int64(totalSize) {
logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
return
}
srcFile, err