gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

functional_tests.go (423661B)


      1 //go:build mint
      2 // +build mint
      3 
      4 /*
      5  * MinIO Go Library for Amazon S3 Compatible Cloud Storage
      6  * Copyright 2015-2020 MinIO, Inc.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 package main
     22 
     23 import (
     24 	"archive/zip"
     25 	"bytes"
     26 	"context"
     27 	"crypto/sha1"
     28 	"encoding/base64"
     29 	"errors"
     30 	"fmt"
     31 	"hash"
     32 	"hash/crc32"
     33 	"io"
     34 	"math/rand"
     35 	"mime/multipart"
     36 	"net/http"
     37 	"net/url"
     38 	"os"
     39 	"path"
     40 	"path/filepath"
     41 	"reflect"
     42 	"runtime"
     43 	"sort"
     44 	"strconv"
     45 	"strings"
     46 	"sync"
     47 	"time"
     48 
     49 	"github.com/dustin/go-humanize"
     50 	jsoniter "github.com/json-iterator/go"
     51 	"github.com/minio/sha256-simd"
     52 	log "github.com/sirupsen/logrus"
     53 
     54 	"github.com/minio/minio-go/v7"
     55 	"github.com/minio/minio-go/v7/pkg/credentials"
     56 	"github.com/minio/minio-go/v7/pkg/encrypt"
     57 	"github.com/minio/minio-go/v7/pkg/notification"
     58 	"github.com/minio/minio-go/v7/pkg/tags"
     59 )
     60 
     61 const letterBytes = "abcdefghijklmnopqrstuvwxyz01234569"
     62 const (
     63 	letterIdxBits = 6                    // 6 bits to represent a letter index
     64 	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
     65 	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
     66 )
     67 
     68 const (
     69 	serverEndpoint = "SERVER_ENDPOINT"
     70 	accessKey      = "ACCESS_KEY"
     71 	secretKey      = "SECRET_KEY"
     72 	enableHTTPS    = "ENABLE_HTTPS"
     73 	enableKMS      = "ENABLE_KMS"
     74 )
     75 
     76 type mintJSONFormatter struct{}
     77 
     78 func (f *mintJSONFormatter) Format(entry *log.Entry) ([]byte, error) {
     79 	data := make(log.Fields, len(entry.Data))
     80 	for k, v := range entry.Data {
     81 		switch v := v.(type) {
     82 		case error:
     83 			// Otherwise errors are ignored by `encoding/json`
     84 			// https://github.com/sirupsen/logrus/issues/137
     85 			data[k] = v.Error()
     86 		default:
     87 			data[k] = v
     88 		}
     89 	}
     90 	json := jsoniter.ConfigCompatibleWithStandardLibrary
     91 	serialized, err := json.Marshal(data)
     92 	if err != nil {
     93 		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
     94 	}
     95 	return append(serialized, '\n'), nil
     96 }
     97 
     98 var readFull = func(r io.Reader, buf []byte) (n int, err error) {
     99 	// ReadFull reads exactly len(buf) bytes from r into buf.
    100 	// It returns the number of bytes copied and an error if
    101 	// fewer bytes were read. The error is EOF only if no bytes
    102 	// were read. If an EOF happens after reading some but not
    103 	// all the bytes, ReadFull returns ErrUnexpectedEOF.
    104 	// On return, n == len(buf) if and only if err == nil.
    105 	// If r returns an error having read at least len(buf) bytes,
    106 	// the error is dropped.
    107 	for n < len(buf) && err == nil {
    108 		var nn int
    109 		nn, err = r.Read(buf[n:])
    110 		// Some spurious io.Reader's return
    111 		// io.ErrUnexpectedEOF when nn == 0
    112 		// this behavior is undocumented
    113 		// so we are on purpose not using io.ReadFull
    114 		// implementation because this can lead
    115 		// to custom handling, to avoid that
    116 		// we simply modify the original io.ReadFull
    117 		// implementation to avoid this issue.
    118 		// io.ErrUnexpectedEOF with nn == 0 really
    119 		// means that io.EOF
    120 		if err == io.ErrUnexpectedEOF && nn == 0 {
    121 			err = io.EOF
    122 		}
    123 		n += nn
    124 	}
    125 	if n >= len(buf) {
    126 		err = nil
    127 	} else if n > 0 && err == io.EOF {
    128 		err = io.ErrUnexpectedEOF
    129 	}
    130 	return
    131 }
    132 
    133 func cleanEmptyEntries(fields log.Fields) log.Fields {
    134 	cleanFields := log.Fields{}
    135 	for k, v := range fields {
    136 		if v != "" {
    137 			cleanFields[k] = v
    138 		}
    139 	}
    140 	return cleanFields
    141 }
    142 
    143 // log successful test runs
    144 func successLogger(testName string, function string, args map[string]interface{}, startTime time.Time) *log.Entry {
    145 	// calculate the test case duration
    146 	duration := time.Since(startTime)
    147 	// log with the fields as per mint
    148 	fields := log.Fields{"name": "minio-go: " + testName, "function": function, "args": args, "duration": duration.Nanoseconds() / 1000000, "status": "PASS"}
    149 	return log.WithFields(cleanEmptyEntries(fields))
    150 }
    151 
    152 // As few of the features are not available in Gateway(s) currently, Check if err value is NotImplemented,
    153 // and log as NA in that case and continue execution. Otherwise log as failure and return
    154 func logError(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) {
    155 	// If server returns NotImplemented we assume it is gateway mode and hence log it as info and move on to next tests
    156 	// Special case for ComposeObject API as it is implemented on client side and adds specific error details like `Error in upload-part-copy` in
    157 	// addition to NotImplemented error returned from server
    158 	if isErrNotImplemented(err) {
    159 		ignoredLog(testName, function, args, startTime, message).Info()
    160 	} else if isRunOnFail() {
    161 		failureLog(testName, function, args, startTime, alert, message, err).Error()
    162 	} else {
    163 		failureLog(testName, function, args, startTime, alert, message, err).Fatal()
    164 	}
    165 }
    166 
    167 // log failed test runs
    168 func failureLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) *log.Entry {
    169 	// calculate the test case duration
    170 	duration := time.Since(startTime)
    171 	var fields log.Fields
    172 	// log with the fields as per mint
    173 	if err != nil {
    174 		fields = log.Fields{
    175 			"name": "minio-go: " + testName, "function": function, "args": args,
    176 			"duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message, "error": err,
    177 		}
    178 	} else {
    179 		fields = log.Fields{
    180 			"name": "minio-go: " + testName, "function": function, "args": args,
    181 			"duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message,
    182 		}
    183 	}
    184 	return log.WithFields(cleanEmptyEntries(fields))
    185 }
    186 
    187 // log not applicable test runs
    188 func ignoredLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string) *log.Entry {
    189 	// calculate the test case duration
    190 	duration := time.Since(startTime)
    191 	// log with the fields as per mint
    192 	fields := log.Fields{
    193 		"name": "minio-go: " + testName, "function": function, "args": args,
    194 		"duration": duration.Nanoseconds() / 1000000, "status": "NA", "alert": strings.Split(alert, " ")[0] + " is NotImplemented",
    195 	}
    196 	return log.WithFields(cleanEmptyEntries(fields))
    197 }
    198 
    199 // Delete objects in given bucket, recursively
    200 func cleanupBucket(bucketName string, c *minio.Client) error {
    201 	// Create a done channel to control 'ListObjectsV2' go routine.
    202 	doneCh := make(chan struct{})
    203 	// Exit cleanly upon return.
    204 	defer close(doneCh)
    205 	// Iterate over all objects in the bucket via listObjectsV2 and delete
    206 	for objCh := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{Recursive: true}) {
    207 		if objCh.Err != nil {
    208 			return objCh.Err
    209 		}
    210 		if objCh.Key != "" {
    211 			err := c.RemoveObject(context.Background(), bucketName, objCh.Key, minio.RemoveObjectOptions{})
    212 			if err != nil {
    213 				return err
    214 			}
    215 		}
    216 	}
    217 	for objPartInfo := range c.ListIncompleteUploads(context.Background(), bucketName, "", true) {
    218 		if objPartInfo.Err != nil {
    219 			return objPartInfo.Err
    220 		}
    221 		if objPartInfo.Key != "" {
    222 			err := c.RemoveIncompleteUpload(context.Background(), bucketName, objPartInfo.Key)
    223 			if err != nil {
    224 				return err
    225 			}
    226 		}
    227 	}
    228 	// objects are already deleted, clear the buckets now
    229 	err := c.RemoveBucket(context.Background(), bucketName)
    230 	if err != nil {
    231 		return err
    232 	}
    233 	return err
    234 }
    235 
    236 func cleanupVersionedBucket(bucketName string, c *minio.Client) error {
    237 	doneCh := make(chan struct{})
    238 	defer close(doneCh)
    239 	for obj := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true}) {
    240 		if obj.Err != nil {
    241 			return obj.Err
    242 		}
    243 		if obj.Key != "" {
    244 			err := c.RemoveObject(context.Background(), bucketName, obj.Key,
    245 				minio.RemoveObjectOptions{VersionID: obj.VersionID, GovernanceBypass: true})
    246 			if err != nil {
    247 				return err
    248 			}
    249 		}
    250 	}
    251 	for objPartInfo := range c.ListIncompleteUploads(context.Background(), bucketName, "", true) {
    252 		if objPartInfo.Err != nil {
    253 			return objPartInfo.Err
    254 		}
    255 		if objPartInfo.Key != "" {
    256 			err := c.RemoveIncompleteUpload(context.Background(), bucketName, objPartInfo.Key)
    257 			if err != nil {
    258 				return err
    259 			}
    260 		}
    261 	}
    262 	// objects are already deleted, clear the buckets now
    263 	err := c.RemoveBucket(context.Background(), bucketName)
    264 	if err != nil {
    265 		for obj := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true}) {
    266 			log.Println("found", obj.Key, obj.VersionID)
    267 		}
    268 		return err
    269 	}
    270 	return err
    271 }
    272 
    273 func isErrNotImplemented(err error) bool {
    274 	return minio.ToErrorResponse(err).Code == "NotImplemented"
    275 }
    276 
    277 func isRunOnFail() bool {
    278 	return os.Getenv("RUN_ON_FAIL") == "1"
    279 }
    280 
    281 func init() {
    282 	// If server endpoint is not set, all tests default to
    283 	// using https://play.min.io
    284 	if os.Getenv(serverEndpoint) == "" {
    285 		os.Setenv(serverEndpoint, "play.min.io")
    286 		os.Setenv(accessKey, "Q3AM3UQ867SPQQA43P2F")
    287 		os.Setenv(secretKey, "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
    288 		os.Setenv(enableHTTPS, "1")
    289 	}
    290 }
    291 
    292 var mintDataDir = os.Getenv("MINT_DATA_DIR")
    293 
    294 func getMintDataDirFilePath(filename string) (fp string) {
    295 	if mintDataDir == "" {
    296 		return
    297 	}
    298 	return filepath.Join(mintDataDir, filename)
    299 }
    300 
    301 func newRandomReader(seed, size int64) io.Reader {
    302 	return io.LimitReader(rand.New(rand.NewSource(seed)), size)
    303 }
    304 
    305 func mustCrcReader(r io.Reader) uint32 {
    306 	crc := crc32.NewIEEE()
    307 	_, err := io.Copy(crc, r)
    308 	if err != nil {
    309 		panic(err)
    310 	}
    311 	return crc.Sum32()
    312 }
    313 
    314 func crcMatches(r io.Reader, want uint32) error {
    315 	crc := crc32.NewIEEE()
    316 	_, err := io.Copy(crc, r)
    317 	if err != nil {
    318 		panic(err)
    319 	}
    320 	got := crc.Sum32()
    321 	if got != want {
    322 		return fmt.Errorf("crc mismatch, want %x, got %x", want, got)
    323 	}
    324 	return nil
    325 }
    326 
    327 func crcMatchesName(r io.Reader, name string) error {
    328 	want := dataFileCRC32[name]
    329 	crc := crc32.NewIEEE()
    330 	_, err := io.Copy(crc, r)
    331 	if err != nil {
    332 		panic(err)
    333 	}
    334 	got := crc.Sum32()
    335 	if got != want {
    336 		return fmt.Errorf("crc mismatch, want %x, got %x", want, got)
    337 	}
    338 	return nil
    339 }
    340 
    341 // read data from file if it exists or optionally create a buffer of particular size
    342 func getDataReader(fileName string) io.ReadCloser {
    343 	if mintDataDir == "" {
    344 		size := int64(dataFileMap[fileName])
    345 		if _, ok := dataFileCRC32[fileName]; !ok {
    346 			dataFileCRC32[fileName] = mustCrcReader(newRandomReader(size, size))
    347 		}
    348 		return io.NopCloser(newRandomReader(size, size))
    349 	}
    350 	reader, _ := os.Open(getMintDataDirFilePath(fileName))
    351 	if _, ok := dataFileCRC32[fileName]; !ok {
    352 		dataFileCRC32[fileName] = mustCrcReader(reader)
    353 		reader.Close()
    354 		reader, _ = os.Open(getMintDataDirFilePath(fileName))
    355 	}
    356 	return reader
    357 }
    358 
    359 // randString generates random names and prepends them with a known prefix.
    360 func randString(n int, src rand.Source, prefix string) string {
    361 	b := make([]byte, n)
    362 	// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
    363 	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
    364 		if remain == 0 {
    365 			cache, remain = src.Int63(), letterIdxMax
    366 		}
    367 		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
    368 			b[i] = letterBytes[idx]
    369 			i--
    370 		}
    371 		cache >>= letterIdxBits
    372 		remain--
    373 	}
    374 	return prefix + string(b[0:30-len(prefix)])
    375 }
    376 
    377 var dataFileMap = map[string]int{
    378 	"datafile-0-b":     0,
    379 	"datafile-1-b":     1,
    380 	"datafile-1-kB":    1 * humanize.KiByte,
    381 	"datafile-10-kB":   10 * humanize.KiByte,
    382 	"datafile-33-kB":   33 * humanize.KiByte,
    383 	"datafile-100-kB":  100 * humanize.KiByte,
    384 	"datafile-1.03-MB": 1056 * humanize.KiByte,
    385 	"datafile-1-MB":    1 * humanize.MiByte,
    386 	"datafile-5-MB":    5 * humanize.MiByte,
    387 	"datafile-6-MB":    6 * humanize.MiByte,
    388 	"datafile-11-MB":   11 * humanize.MiByte,
    389 	"datafile-65-MB":   65 * humanize.MiByte,
    390 	"datafile-129-MB":  129 * humanize.MiByte,
    391 }
    392 
    393 var dataFileCRC32 = map[string]uint32{}
    394 
    395 func isFullMode() bool {
    396 	return os.Getenv("MINT_MODE") == "full"
    397 }
    398 
    399 func getFuncName() string {
    400 	return getFuncNameLoc(2)
    401 }
    402 
    403 func getFuncNameLoc(caller int) string {
    404 	pc, _, _, _ := runtime.Caller(caller)
    405 	return strings.TrimPrefix(runtime.FuncForPC(pc).Name(), "main.")
    406 }
    407 
    408 // Tests bucket re-create errors.
    409 func testMakeBucketError() {
    410 	region := "eu-central-1"
    411 
    412 	// initialize logging params
    413 	startTime := time.Now()
    414 	testName := getFuncName()
    415 	function := "MakeBucket(bucketName, region)"
    416 	// initialize logging params
    417 	args := map[string]interface{}{
    418 		"bucketName": "",
    419 		"region":     region,
    420 	}
    421 
    422 	// Seed random based on current time.
    423 	rand.Seed(time.Now().Unix())
    424 
    425 	// Instantiate new minio client object.
    426 	c, err := minio.New(os.Getenv(serverEndpoint),
    427 		&minio.Options{
    428 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    429 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    430 		})
    431 	if err != nil {
    432 		logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
    433 		return
    434 	}
    435 
    436 	// Enable tracing, write to stderr.
    437 	// c.TraceOn(os.Stderr)
    438 
    439 	// Set user agent.
    440 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    441 
    442 	// Generate a new random bucket name.
    443 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    444 	args["bucketName"] = bucketName
    445 
    446 	// Make a new bucket in 'eu-central-1'.
    447 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region}); err != nil {
    448 		logError(testName, function, args, startTime, "", "MakeBucket Failed", err)
    449 		return
    450 	}
    451 	defer cleanupBucket(bucketName, c)
    452 
    453 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region}); err == nil {
    454 		logError(testName, function, args, startTime, "", "Bucket already exists", err)
    455 		return
    456 	}
    457 	// Verify valid error response from server.
    458 	if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
    459 		minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
    460 		logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
    461 		return
    462 	}
    463 
    464 	successLogger(testName, function, args, startTime).Info()
    465 }
    466 
    467 func testMetadataSizeLimit() {
    468 	startTime := time.Now()
    469 	testName := getFuncName()
    470 	function := "PutObject(bucketName, objectName, reader, objectSize, opts)"
    471 	args := map[string]interface{}{
    472 		"bucketName":        "",
    473 		"objectName":        "",
    474 		"opts.UserMetadata": "",
    475 	}
    476 	rand.Seed(startTime.Unix())
    477 
    478 	// Instantiate new minio client object.
    479 	c, err := minio.New(os.Getenv(serverEndpoint),
    480 		&minio.Options{
    481 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    482 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    483 		})
    484 	if err != nil {
    485 		logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
    486 		return
    487 	}
    488 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    489 
    490 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    491 	args["bucketName"] = bucketName
    492 
    493 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
    494 	args["objectName"] = objectName
    495 
    496 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
    497 	if err != nil {
    498 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
    499 		return
    500 	}
    501 
    502 	defer cleanupBucket(bucketName, c)
    503 
    504 	const HeaderSizeLimit = 8 * 1024
    505 	const UserMetadataLimit = 2 * 1024
    506 
    507 	// Meta-data greater than the 2 KB limit of AWS - PUT calls with this meta-data should fail
    508 	metadata := make(map[string]string)
    509 	metadata["X-Amz-Meta-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+UserMetadataLimit-len("X-Amz-Meta-Mint-Test")))
    510 	args["metadata"] = fmt.Sprint(metadata)
    511 
    512 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
    513 	if err == nil {
    514 		logError(testName, function, args, startTime, "", "Created object with user-defined metadata exceeding metadata size limits", nil)
    515 		return
    516 	}
    517 
    518 	// Meta-data (headers) greater than the 8 KB limit of AWS - PUT calls with this meta-data should fail
    519 	metadata = make(map[string]string)
    520 	metadata["X-Amz-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+HeaderSizeLimit-len("X-Amz-Mint-Test")))
    521 	args["metadata"] = fmt.Sprint(metadata)
    522 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
    523 	if err == nil {
    524 		logError(testName, function, args, startTime, "", "Created object with headers exceeding header size limits", nil)
    525 		return
    526 	}
    527 
    528 	successLogger(testName, function, args, startTime).Info()
    529 }
    530 
    531 // Tests various bucket supported formats.
    532 func testMakeBucketRegions() {
    533 	region := "eu-central-1"
    534 	// initialize logging params
    535 	startTime := time.Now()
    536 	testName := getFuncName()
    537 	function := "MakeBucket(bucketName, region)"
    538 	// initialize logging params
    539 	args := map[string]interface{}{
    540 		"bucketName": "",
    541 		"region":     region,
    542 	}
    543 
    544 	// Seed random based on current time.
    545 	rand.Seed(time.Now().Unix())
    546 
    547 	// Instantiate new minio client object.
    548 	c, err := minio.New(os.Getenv(serverEndpoint),
    549 		&minio.Options{
    550 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    551 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    552 		})
    553 	if err != nil {
    554 		logError(testName, function, args, startTime, "", "MinIO client creation failed", err)
    555 		return
    556 	}
    557 
    558 	// Enable tracing, write to stderr.
    559 	// c.TraceOn(os.Stderr)
    560 
    561 	// Set user agent.
    562 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    563 
    564 	// Generate a new random bucket name.
    565 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    566 	args["bucketName"] = bucketName
    567 
    568 	// Make a new bucket in 'eu-central-1'.
    569 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region}); err != nil {
    570 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
    571 		return
    572 	}
    573 
    574 	// Delete all objects and buckets
    575 	if err = cleanupBucket(bucketName, c); err != nil {
    576 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
    577 		return
    578 	}
    579 
    580 	// Make a new bucket with '.' in its name, in 'us-west-2'. This
    581 	// request is internally staged into a path style instead of
    582 	// virtual host style.
    583 	region = "us-west-2"
    584 	args["region"] = region
    585 	if err = c.MakeBucket(context.Background(), bucketName+".withperiod", minio.MakeBucketOptions{Region: region}); err != nil {
    586 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
    587 		return
    588 	}
    589 
    590 	// Delete all objects and buckets
    591 	if err = cleanupBucket(bucketName+".withperiod", c); err != nil {
    592 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
    593 		return
    594 	}
    595 	successLogger(testName, function, args, startTime).Info()
    596 }
    597 
    598 // Test PutObject using a large data to trigger multipart readat
    599 func testPutObjectReadAt() {
    600 	// initialize logging params
    601 	startTime := time.Now()
    602 	testName := getFuncName()
    603 	function := "PutObject(bucketName, objectName, reader, opts)"
    604 	args := map[string]interface{}{
    605 		"bucketName": "",
    606 		"objectName": "",
    607 		"opts":       "objectContentType",
    608 	}
    609 
    610 	// Seed random based on current time.
    611 	rand.Seed(time.Now().Unix())
    612 
    613 	// Instantiate new minio client object.
    614 	c, err := minio.New(os.Getenv(serverEndpoint),
    615 		&minio.Options{
    616 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    617 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    618 		})
    619 	if err != nil {
    620 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
    621 		return
    622 	}
    623 
    624 	// Enable tracing, write to stderr.
    625 	// c.TraceOn(os.Stderr)
    626 
    627 	// Set user agent.
    628 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    629 
    630 	// Generate a new random bucket name.
    631 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    632 	args["bucketName"] = bucketName
    633 
    634 	// Make a new bucket.
    635 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
    636 	if err != nil {
    637 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
    638 		return
    639 	}
    640 
    641 	defer cleanupBucket(bucketName, c)
    642 
    643 	bufSize := dataFileMap["datafile-129-MB"]
    644 	reader := getDataReader("datafile-129-MB")
    645 	defer reader.Close()
    646 
    647 	// Save the data
    648 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
    649 	args["objectName"] = objectName
    650 
    651 	// Object content type
    652 	objectContentType := "binary/octet-stream"
    653 	args["objectContentType"] = objectContentType
    654 
    655 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: objectContentType})
    656 	if err != nil {
    657 		logError(testName, function, args, startTime, "", "PutObject failed", err)
    658 		return
    659 	}
    660 
    661 	// Read the data back
    662 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
    663 	if err != nil {
    664 		logError(testName, function, args, startTime, "", "Get Object failed", err)
    665 		return
    666 	}
    667 
    668 	st, err := r.Stat()
    669 	if err != nil {
    670 		logError(testName, function, args, startTime, "", "Stat Object failed", err)
    671 		return
    672 	}
    673 	if st.Size != int64(bufSize) {
    674 		logError(testName, function, args, startTime, "", fmt.Sprintf("Number of bytes in stat does not match, expected %d got %d", bufSize, st.Size), err)
    675 		return
    676 	}
    677 	if st.ContentType != objectContentType && st.ContentType != "application/octet-stream" {
    678 		logError(testName, function, args, startTime, "", "Content types don't match", err)
    679 		return
    680 	}
    681 	if err := crcMatchesName(r, "datafile-129-MB"); err != nil {
    682 		logError(testName, function, args, startTime, "", "data CRC check failed", err)
    683 		return
    684 	}
    685 	if err := r.Close(); err != nil {
    686 		logError(testName, function, args, startTime, "", "Object Close failed", err)
    687 		return
    688 	}
    689 	if err := r.Close(); err == nil {
    690 		logError(testName, function, args, startTime, "", "Object is already closed, didn't return error on Close", err)
    691 		return
    692 	}
    693 
    694 	successLogger(testName, function, args, startTime).Info()
    695 }
    696 
    697 func testListObjectVersions() {
    698 	// initialize logging params
    699 	startTime := time.Now()
    700 	testName := getFuncName()
    701 	function := "ListObjectVersions(bucketName, prefix, recursive)"
    702 	args := map[string]interface{}{
    703 		"bucketName": "",
    704 		"prefix":     "",
    705 		"recursive":  "",
    706 	}
    707 
    708 	// Seed random based on current time.
    709 	rand.Seed(time.Now().Unix())
    710 
    711 	// Instantiate new minio client object.
    712 	c, err := minio.New(os.Getenv(serverEndpoint),
    713 		&minio.Options{
    714 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    715 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    716 		})
    717 	if err != nil {
    718 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
    719 		return
    720 	}
    721 
    722 	// Enable tracing, write to stderr.
    723 	// c.TraceOn(os.Stderr)
    724 
    725 	// Set user agent.
    726 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    727 
    728 	// Generate a new random bucket name.
    729 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    730 	args["bucketName"] = bucketName
    731 
    732 	// Make a new bucket.
    733 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
    734 	if err != nil {
    735 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
    736 		return
    737 	}
    738 
    739 	err = c.EnableVersioning(context.Background(), bucketName)
    740 	if err != nil {
    741 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
    742 		return
    743 	}
    744 
    745 	// Save the data
    746 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
    747 	args["objectName"] = objectName
    748 
    749 	bufSize := dataFileMap["datafile-10-kB"]
    750 	reader := getDataReader("datafile-10-kB")
    751 
    752 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
    753 	if err != nil {
    754 		logError(testName, function, args, startTime, "", "PutObject failed", err)
    755 		return
    756 	}
    757 	reader.Close()
    758 
    759 	bufSize = dataFileMap["datafile-1-b"]
    760 	reader = getDataReader("datafile-1-b")
    761 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
    762 	if err != nil {
    763 		logError(testName, function, args, startTime, "", "PutObject failed", err)
    764 		return
    765 	}
    766 	reader.Close()
    767 
    768 	err = c.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
    769 	if err != nil {
    770 		logError(testName, function, args, startTime, "", "Unexpected object deletion", err)
    771 		return
    772 	}
    773 
    774 	var deleteMarkers, versions int
    775 
    776 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
    777 	for info := range objectsInfo {
    778 		if info.Err != nil {
    779 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
    780 			return
    781 		}
    782 		if info.Key != objectName {
    783 			logError(testName, function, args, startTime, "", "Unexpected object name in listing objects", nil)
    784 			return
    785 		}
    786 		if info.VersionID == "" {
    787 			logError(testName, function, args, startTime, "", "Unexpected version id in listing objects", nil)
    788 			return
    789 		}
    790 		if info.IsDeleteMarker {
    791 			deleteMarkers++
    792 			if !info.IsLatest {
    793 				logError(testName, function, args, startTime, "", "Unexpected IsLatest field in listing objects", nil)
    794 				return
    795 			}
    796 		} else {
    797 			versions++
    798 		}
    799 	}
    800 
    801 	if deleteMarkers != 1 {
    802 		logError(testName, function, args, startTime, "", "Unexpected number of DeleteMarker elements in listing objects", nil)
    803 		return
    804 	}
    805 
    806 	if versions != 2 {
    807 		logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
    808 		return
    809 	}
    810 
    811 	// Delete all objects and their versions as long as the bucket itself
    812 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
    813 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
    814 		return
    815 	}
    816 
    817 	successLogger(testName, function, args, startTime).Info()
    818 }
    819 
    820 func testStatObjectWithVersioning() {
    821 	// initialize logging params
    822 	startTime := time.Now()
    823 	testName := getFuncName()
    824 	function := "StatObject"
    825 	args := map[string]interface{}{}
    826 
    827 	// Seed random based on current time.
    828 	rand.Seed(time.Now().Unix())
    829 
    830 	// Instantiate new minio client object.
    831 	c, err := minio.New(os.Getenv(serverEndpoint),
    832 		&minio.Options{
    833 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    834 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    835 		})
    836 	if err != nil {
    837 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
    838 		return
    839 	}
    840 
    841 	// Enable tracing, write to stderr.
    842 	// c.TraceOn(os.Stderr)
    843 
    844 	// Set user agent.
    845 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    846 
    847 	// Generate a new random bucket name.
    848 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    849 	args["bucketName"] = bucketName
    850 
    851 	// Make a new bucket.
    852 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
    853 	if err != nil {
    854 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
    855 		return
    856 	}
    857 
    858 	err = c.EnableVersioning(context.Background(), bucketName)
    859 	if err != nil {
    860 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
    861 		return
    862 	}
    863 
    864 	// Save the data
    865 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
    866 	args["objectName"] = objectName
    867 
    868 	bufSize := dataFileMap["datafile-10-kB"]
    869 	reader := getDataReader("datafile-10-kB")
    870 
    871 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
    872 	if err != nil {
    873 		logError(testName, function, args, startTime, "", "PutObject failed", err)
    874 		return
    875 	}
    876 	reader.Close()
    877 
    878 	bufSize = dataFileMap["datafile-1-b"]
    879 	reader = getDataReader("datafile-1-b")
    880 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
    881 	if err != nil {
    882 		logError(testName, function, args, startTime, "", "PutObject failed", err)
    883 		return
    884 	}
    885 	reader.Close()
    886 
    887 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
    888 
    889 	var results []minio.ObjectInfo
    890 	for info := range objectsInfo {
    891 		if info.Err != nil {
    892 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
    893 			return
    894 		}
    895 		results = append(results, info)
    896 	}
    897 
    898 	if len(results) != 2 {
    899 		logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
    900 		return
    901 	}
    902 
    903 	for i := 0; i < len(results); i++ {
    904 		opts := minio.StatObjectOptions{VersionID: results[i].VersionID}
    905 		statInfo, err := c.StatObject(context.Background(), bucketName, objectName, opts)
    906 		if err != nil {
    907 			logError(testName, function, args, startTime, "", "error during HEAD object", err)
    908 			return
    909 		}
    910 		if statInfo.VersionID == "" || statInfo.VersionID != results[i].VersionID {
    911 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected version id", err)
    912 			return
    913 		}
    914 		if statInfo.ETag != results[i].ETag {
    915 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected ETag", err)
    916 			return
    917 		}
    918 		if statInfo.LastModified.Unix() != results[i].LastModified.Unix() {
    919 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Last-Modified", err)
    920 			return
    921 		}
    922 		if statInfo.Size != results[i].Size {
    923 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Content-Length", err)
    924 			return
    925 		}
    926 	}
    927 
    928 	// Delete all objects and their versions as long as the bucket itself
    929 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
    930 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
    931 		return
    932 	}
    933 
    934 	successLogger(testName, function, args, startTime).Info()
    935 }
    936 
    937 func testGetObjectWithVersioning() {
    938 	// initialize logging params
    939 	startTime := time.Now()
    940 	testName := getFuncName()
    941 	function := "GetObject()"
    942 	args := map[string]interface{}{}
    943 
    944 	// Seed random based on current time.
    945 	rand.Seed(time.Now().Unix())
    946 
    947 	// Instantiate new minio client object.
    948 	c, err := minio.New(os.Getenv(serverEndpoint),
    949 		&minio.Options{
    950 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
    951 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
    952 		})
    953 	if err != nil {
    954 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
    955 		return
    956 	}
    957 
    958 	// Enable tracing, write to stderr.
    959 	// c.TraceOn(os.Stderr)
    960 
    961 	// Set user agent.
    962 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
    963 
    964 	// Generate a new random bucket name.
    965 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
    966 	args["bucketName"] = bucketName
    967 
    968 	// Make a new bucket.
    969 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
    970 	if err != nil {
    971 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
    972 		return
    973 	}
    974 
    975 	err = c.EnableVersioning(context.Background(), bucketName)
    976 	if err != nil {
    977 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
    978 		return
    979 	}
    980 
    981 	// Save the data
    982 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
    983 	args["objectName"] = objectName
    984 
    985 	// Save the contents of datafiles to check with GetObject() reader output later
    986 	var buffers [][]byte
    987 	testFiles := []string{"datafile-1-b", "datafile-10-kB"}
    988 
    989 	for _, testFile := range testFiles {
    990 		r := getDataReader(testFile)
    991 		buf, err := io.ReadAll(r)
    992 		if err != nil {
    993 			logError(testName, function, args, startTime, "", "unexpected failure", err)
    994 			return
    995 		}
    996 		r.Close()
    997 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
    998 		if err != nil {
    999 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1000 			return
   1001 		}
   1002 		buffers = append(buffers, buf)
   1003 	}
   1004 
   1005 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1006 
   1007 	var results []minio.ObjectInfo
   1008 	for info := range objectsInfo {
   1009 		if info.Err != nil {
   1010 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1011 			return
   1012 		}
   1013 		results = append(results, info)
   1014 	}
   1015 
   1016 	if len(results) != 2 {
   1017 		logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
   1018 		return
   1019 	}
   1020 
   1021 	sort.SliceStable(results, func(i, j int) bool {
   1022 		return results[i].Size < results[j].Size
   1023 	})
   1024 
   1025 	sort.SliceStable(buffers, func(i, j int) bool {
   1026 		return len(buffers[i]) < len(buffers[j])
   1027 	})
   1028 
   1029 	for i := 0; i < len(results); i++ {
   1030 		opts := minio.GetObjectOptions{VersionID: results[i].VersionID}
   1031 		reader, err := c.GetObject(context.Background(), bucketName, objectName, opts)
   1032 		if err != nil {
   1033 			logError(testName, function, args, startTime, "", "error during  GET object", err)
   1034 			return
   1035 		}
   1036 		statInfo, err := reader.Stat()
   1037 		if err != nil {
   1038 			logError(testName, function, args, startTime, "", "error during calling reader.Stat()", err)
   1039 			return
   1040 		}
   1041 		if statInfo.ETag != results[i].ETag {
   1042 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected ETag", err)
   1043 			return
   1044 		}
   1045 		if statInfo.LastModified.Unix() != results[i].LastModified.Unix() {
   1046 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Last-Modified", err)
   1047 			return
   1048 		}
   1049 		if statInfo.Size != results[i].Size {
   1050 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Content-Length", err)
   1051 			return
   1052 		}
   1053 
   1054 		tmpBuffer := bytes.NewBuffer([]byte{})
   1055 		_, err = io.Copy(tmpBuffer, reader)
   1056 		if err != nil {
   1057 			logError(testName, function, args, startTime, "", "unexpected io.Copy()", err)
   1058 			return
   1059 		}
   1060 
   1061 		if !bytes.Equal(tmpBuffer.Bytes(), buffers[i]) {
   1062 			logError(testName, function, args, startTime, "", "unexpected content of GetObject()", err)
   1063 			return
   1064 		}
   1065 	}
   1066 
   1067 	// Delete all objects and their versions as long as the bucket itself
   1068 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   1069 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1070 		return
   1071 	}
   1072 
   1073 	successLogger(testName, function, args, startTime).Info()
   1074 }
   1075 
   1076 func testPutObjectWithVersioning() {
   1077 	// initialize logging params
   1078 	startTime := time.Now()
   1079 	testName := getFuncName()
   1080 	function := "GetObject()"
   1081 	args := map[string]interface{}{}
   1082 
   1083 	// Seed random based on current time.
   1084 	rand.Seed(time.Now().Unix())
   1085 
   1086 	// Instantiate new minio client object.
   1087 	c, err := minio.New(os.Getenv(serverEndpoint),
   1088 		&minio.Options{
   1089 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1090 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1091 		})
   1092 	if err != nil {
   1093 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1094 		return
   1095 	}
   1096 
   1097 	// Enable tracing, write to stderr.
   1098 	// c.TraceOn(os.Stderr)
   1099 
   1100 	// Set user agent.
   1101 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1102 
   1103 	// Generate a new random bucket name.
   1104 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1105 	args["bucketName"] = bucketName
   1106 
   1107 	// Make a new bucket.
   1108 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1109 	if err != nil {
   1110 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1111 		return
   1112 	}
   1113 
   1114 	err = c.EnableVersioning(context.Background(), bucketName)
   1115 	if err != nil {
   1116 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1117 		return
   1118 	}
   1119 
   1120 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1121 	args["objectName"] = objectName
   1122 
   1123 	const n = 10
   1124 	// Read input...
   1125 
   1126 	// Save the data concurrently.
   1127 	var wg sync.WaitGroup
   1128 	wg.Add(n)
   1129 	buffers := make([][]byte, n)
   1130 	var errs [n]error
   1131 	for i := 0; i < n; i++ {
   1132 		r := newRandomReader(int64((1<<20)*i+i), int64(i))
   1133 		buf, err := io.ReadAll(r)
   1134 		if err != nil {
   1135 			logError(testName, function, args, startTime, "", "unexpected failure", err)
   1136 			return
   1137 		}
   1138 		buffers[i] = buf
   1139 
   1140 		go func(i int) {
   1141 			defer wg.Done()
   1142 			_, errs[i] = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{PartSize: 5 << 20})
   1143 		}(i)
   1144 	}
   1145 	wg.Wait()
   1146 	for _, err := range errs {
   1147 		if err != nil {
   1148 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1149 			return
   1150 		}
   1151 	}
   1152 
   1153 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1154 	var results []minio.ObjectInfo
   1155 	for info := range objectsInfo {
   1156 		if info.Err != nil {
   1157 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1158 			return
   1159 		}
   1160 		results = append(results, info)
   1161 	}
   1162 
   1163 	if len(results) != n {
   1164 		logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
   1165 		return
   1166 	}
   1167 
   1168 	sort.Slice(results, func(i, j int) bool {
   1169 		return results[i].Size < results[j].Size
   1170 	})
   1171 
   1172 	sort.Slice(buffers, func(i, j int) bool {
   1173 		return len(buffers[i]) < len(buffers[j])
   1174 	})
   1175 
   1176 	for i := 0; i < len(results); i++ {
   1177 		opts := minio.GetObjectOptions{VersionID: results[i].VersionID}
   1178 		reader, err := c.GetObject(context.Background(), bucketName, objectName, opts)
   1179 		if err != nil {
   1180 			logError(testName, function, args, startTime, "", "error during  GET object", err)
   1181 			return
   1182 		}
   1183 		statInfo, err := reader.Stat()
   1184 		if err != nil {
   1185 			logError(testName, function, args, startTime, "", "error during calling reader.Stat()", err)
   1186 			return
   1187 		}
   1188 		if statInfo.ETag != results[i].ETag {
   1189 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected ETag", err)
   1190 			return
   1191 		}
   1192 		if statInfo.LastModified.Unix() != results[i].LastModified.Unix() {
   1193 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Last-Modified", err)
   1194 			return
   1195 		}
   1196 		if statInfo.Size != results[i].Size {
   1197 			logError(testName, function, args, startTime, "", "error during HEAD object, unexpected Content-Length", err)
   1198 			return
   1199 		}
   1200 
   1201 		tmpBuffer := bytes.NewBuffer([]byte{})
   1202 		_, err = io.Copy(tmpBuffer, reader)
   1203 		if err != nil {
   1204 			logError(testName, function, args, startTime, "", "unexpected io.Copy()", err)
   1205 			return
   1206 		}
   1207 
   1208 		if !bytes.Equal(tmpBuffer.Bytes(), buffers[i]) {
   1209 			logError(testName, function, args, startTime, "", "unexpected content of GetObject()", err)
   1210 			return
   1211 		}
   1212 	}
   1213 
   1214 	// Delete all objects and their versions as long as the bucket itself
   1215 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   1216 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1217 		return
   1218 	}
   1219 
   1220 	successLogger(testName, function, args, startTime).Info()
   1221 }
   1222 
   1223 func testCopyObjectWithVersioning() {
   1224 	// initialize logging params
   1225 	startTime := time.Now()
   1226 	testName := getFuncName()
   1227 	function := "CopyObject()"
   1228 	args := map[string]interface{}{}
   1229 
   1230 	// Seed random based on current time.
   1231 	rand.Seed(time.Now().Unix())
   1232 
   1233 	// Instantiate new minio client object.
   1234 	c, err := minio.New(os.Getenv(serverEndpoint),
   1235 		&minio.Options{
   1236 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1237 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1238 		})
   1239 	if err != nil {
   1240 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1241 		return
   1242 	}
   1243 
   1244 	// Enable tracing, write to stderr.
   1245 	// c.TraceOn(os.Stderr)
   1246 
   1247 	// Set user agent.
   1248 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1249 
   1250 	// Generate a new random bucket name.
   1251 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1252 	args["bucketName"] = bucketName
   1253 
   1254 	// Make a new bucket.
   1255 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1256 	if err != nil {
   1257 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1258 		return
   1259 	}
   1260 
   1261 	err = c.EnableVersioning(context.Background(), bucketName)
   1262 	if err != nil {
   1263 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1264 		return
   1265 	}
   1266 
   1267 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1268 	args["objectName"] = objectName
   1269 
   1270 	testFiles := []string{"datafile-1-b", "datafile-10-kB"}
   1271 	for _, testFile := range testFiles {
   1272 		r := getDataReader(testFile)
   1273 		buf, err := io.ReadAll(r)
   1274 		if err != nil {
   1275 			logError(testName, function, args, startTime, "", "unexpected failure", err)
   1276 			return
   1277 		}
   1278 		r.Close()
   1279 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
   1280 		if err != nil {
   1281 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1282 			return
   1283 		}
   1284 	}
   1285 
   1286 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1287 	var infos []minio.ObjectInfo
   1288 	for info := range objectsInfo {
   1289 		if info.Err != nil {
   1290 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1291 			return
   1292 		}
   1293 		infos = append(infos, info)
   1294 	}
   1295 
   1296 	sort.Slice(infos, func(i, j int) bool {
   1297 		return infos[i].Size < infos[j].Size
   1298 	})
   1299 
   1300 	reader, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{VersionID: infos[0].VersionID})
   1301 	if err != nil {
   1302 		logError(testName, function, args, startTime, "", "GetObject of the oldest version content failed", err)
   1303 		return
   1304 	}
   1305 
   1306 	oldestContent, err := io.ReadAll(reader)
   1307 	if err != nil {
   1308 		logError(testName, function, args, startTime, "", "Reading the oldest object version failed", err)
   1309 		return
   1310 	}
   1311 
   1312 	// Copy Source
   1313 	srcOpts := minio.CopySrcOptions{
   1314 		Bucket:    bucketName,
   1315 		Object:    objectName,
   1316 		VersionID: infos[0].VersionID,
   1317 	}
   1318 	args["src"] = srcOpts
   1319 
   1320 	dstOpts := minio.CopyDestOptions{
   1321 		Bucket: bucketName,
   1322 		Object: objectName + "-copy",
   1323 	}
   1324 	args["dst"] = dstOpts
   1325 
   1326 	// Perform the Copy
   1327 	if _, err = c.CopyObject(context.Background(), dstOpts, srcOpts); err != nil {
   1328 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
   1329 		return
   1330 	}
   1331 
   1332 	// Destination object
   1333 	readerCopy, err := c.GetObject(context.Background(), bucketName, objectName+"-copy", minio.GetObjectOptions{})
   1334 	if err != nil {
   1335 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   1336 		return
   1337 	}
   1338 	defer readerCopy.Close()
   1339 
   1340 	newestContent, err := io.ReadAll(readerCopy)
   1341 	if err != nil {
   1342 		logError(testName, function, args, startTime, "", "Reading from GetObject reader failed", err)
   1343 		return
   1344 	}
   1345 
   1346 	if len(newestContent) == 0 || !bytes.Equal(oldestContent, newestContent) {
   1347 		logError(testName, function, args, startTime, "", "Unexpected destination object content", err)
   1348 		return
   1349 	}
   1350 
   1351 	// Delete all objects and their versions as long as the bucket itself
   1352 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   1353 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1354 		return
   1355 	}
   1356 
   1357 	successLogger(testName, function, args, startTime).Info()
   1358 }
   1359 
   1360 func testConcurrentCopyObjectWithVersioning() {
   1361 	// initialize logging params
   1362 	startTime := time.Now()
   1363 	testName := getFuncName()
   1364 	function := "CopyObject()"
   1365 	args := map[string]interface{}{}
   1366 
   1367 	// Seed random based on current time.
   1368 	rand.Seed(time.Now().Unix())
   1369 
   1370 	// Instantiate new minio client object.
   1371 	c, err := minio.New(os.Getenv(serverEndpoint),
   1372 		&minio.Options{
   1373 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1374 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1375 		})
   1376 	if err != nil {
   1377 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1378 		return
   1379 	}
   1380 
   1381 	// Enable tracing, write to stderr.
   1382 	// c.TraceOn(os.Stderr)
   1383 
   1384 	// Set user agent.
   1385 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1386 
   1387 	// Generate a new random bucket name.
   1388 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1389 	args["bucketName"] = bucketName
   1390 
   1391 	// Make a new bucket.
   1392 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1393 	if err != nil {
   1394 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1395 		return
   1396 	}
   1397 
   1398 	err = c.EnableVersioning(context.Background(), bucketName)
   1399 	if err != nil {
   1400 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1401 		return
   1402 	}
   1403 
   1404 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1405 	args["objectName"] = objectName
   1406 
   1407 	testFiles := []string{"datafile-10-kB"}
   1408 	for _, testFile := range testFiles {
   1409 		r := getDataReader(testFile)
   1410 		buf, err := io.ReadAll(r)
   1411 		if err != nil {
   1412 			logError(testName, function, args, startTime, "", "unexpected failure", err)
   1413 			return
   1414 		}
   1415 		r.Close()
   1416 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
   1417 		if err != nil {
   1418 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1419 			return
   1420 		}
   1421 	}
   1422 
   1423 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1424 	var infos []minio.ObjectInfo
   1425 	for info := range objectsInfo {
   1426 		if info.Err != nil {
   1427 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1428 			return
   1429 		}
   1430 		infos = append(infos, info)
   1431 	}
   1432 
   1433 	sort.Slice(infos, func(i, j int) bool {
   1434 		return infos[i].Size < infos[j].Size
   1435 	})
   1436 
   1437 	reader, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{VersionID: infos[0].VersionID})
   1438 	if err != nil {
   1439 		logError(testName, function, args, startTime, "", "GetObject of the oldest version content failed", err)
   1440 		return
   1441 	}
   1442 
   1443 	oldestContent, err := io.ReadAll(reader)
   1444 	if err != nil {
   1445 		logError(testName, function, args, startTime, "", "Reading the oldest object version failed", err)
   1446 		return
   1447 	}
   1448 
   1449 	// Copy Source
   1450 	srcOpts := minio.CopySrcOptions{
   1451 		Bucket:    bucketName,
   1452 		Object:    objectName,
   1453 		VersionID: infos[0].VersionID,
   1454 	}
   1455 	args["src"] = srcOpts
   1456 
   1457 	dstOpts := minio.CopyDestOptions{
   1458 		Bucket: bucketName,
   1459 		Object: objectName + "-copy",
   1460 	}
   1461 	args["dst"] = dstOpts
   1462 
   1463 	// Perform the Copy concurrently
   1464 	const n = 10
   1465 	var wg sync.WaitGroup
   1466 	wg.Add(n)
   1467 	var errs [n]error
   1468 	for i := 0; i < n; i++ {
   1469 		go func(i int) {
   1470 			defer wg.Done()
   1471 			_, errs[i] = c.CopyObject(context.Background(), dstOpts, srcOpts)
   1472 		}(i)
   1473 	}
   1474 	wg.Wait()
   1475 	for _, err := range errs {
   1476 		if err != nil {
   1477 			logError(testName, function, args, startTime, "", "CopyObject failed", err)
   1478 			return
   1479 		}
   1480 	}
   1481 
   1482 	objectsInfo = c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: false, Prefix: dstOpts.Object})
   1483 	infos = []minio.ObjectInfo{}
   1484 	for info := range objectsInfo {
   1485 		// Destination object
   1486 		readerCopy, err := c.GetObject(context.Background(), bucketName, objectName+"-copy", minio.GetObjectOptions{VersionID: info.VersionID})
   1487 		if err != nil {
   1488 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   1489 			return
   1490 		}
   1491 		defer readerCopy.Close()
   1492 
   1493 		newestContent, err := io.ReadAll(readerCopy)
   1494 		if err != nil {
   1495 			logError(testName, function, args, startTime, "", "Reading from GetObject reader failed", err)
   1496 			return
   1497 		}
   1498 
   1499 		if len(newestContent) == 0 || !bytes.Equal(oldestContent, newestContent) {
   1500 			logError(testName, function, args, startTime, "", "Unexpected destination object content", err)
   1501 			return
   1502 		}
   1503 		infos = append(infos, info)
   1504 	}
   1505 
   1506 	if len(infos) != n {
   1507 		logError(testName, function, args, startTime, "", "Unexpected number of Version elements in listing objects", nil)
   1508 		return
   1509 	}
   1510 
   1511 	// Delete all objects and their versions as long as the bucket itself
   1512 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   1513 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1514 		return
   1515 	}
   1516 
   1517 	successLogger(testName, function, args, startTime).Info()
   1518 }
   1519 
   1520 func testComposeObjectWithVersioning() {
   1521 	// initialize logging params
   1522 	startTime := time.Now()
   1523 	testName := getFuncName()
   1524 	function := "ComposeObject()"
   1525 	args := map[string]interface{}{}
   1526 
   1527 	// Seed random based on current time.
   1528 	rand.Seed(time.Now().Unix())
   1529 
   1530 	// Instantiate new minio client object.
   1531 	c, err := minio.New(os.Getenv(serverEndpoint),
   1532 		&minio.Options{
   1533 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1534 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1535 		})
   1536 	if err != nil {
   1537 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1538 		return
   1539 	}
   1540 
   1541 	// Enable tracing, write to stderr.
   1542 	// c.TraceOn(os.Stderr)
   1543 
   1544 	// Set user agent.
   1545 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1546 
   1547 	// Generate a new random bucket name.
   1548 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1549 	args["bucketName"] = bucketName
   1550 
   1551 	// Make a new bucket.
   1552 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1553 	if err != nil {
   1554 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1555 		return
   1556 	}
   1557 
   1558 	err = c.EnableVersioning(context.Background(), bucketName)
   1559 	if err != nil {
   1560 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1561 		return
   1562 	}
   1563 
   1564 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1565 	args["objectName"] = objectName
   1566 
   1567 	// var testFiles = []string{"datafile-5-MB", "datafile-10-kB"}
   1568 	testFiles := []string{"datafile-5-MB", "datafile-10-kB"}
   1569 	var testFilesBytes [][]byte
   1570 
   1571 	for _, testFile := range testFiles {
   1572 		r := getDataReader(testFile)
   1573 		buf, err := io.ReadAll(r)
   1574 		if err != nil {
   1575 			logError(testName, function, args, startTime, "", "unexpected failure", err)
   1576 			return
   1577 		}
   1578 		r.Close()
   1579 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
   1580 		if err != nil {
   1581 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1582 			return
   1583 		}
   1584 		testFilesBytes = append(testFilesBytes, buf)
   1585 	}
   1586 
   1587 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1588 
   1589 	var results []minio.ObjectInfo
   1590 	for info := range objectsInfo {
   1591 		if info.Err != nil {
   1592 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1593 			return
   1594 		}
   1595 		results = append(results, info)
   1596 	}
   1597 
   1598 	sort.SliceStable(results, func(i, j int) bool {
   1599 		return results[i].Size > results[j].Size
   1600 	})
   1601 
   1602 	// Source objects to concatenate. We also specify decryption
   1603 	// key for each
   1604 	src1 := minio.CopySrcOptions{
   1605 		Bucket:    bucketName,
   1606 		Object:    objectName,
   1607 		VersionID: results[0].VersionID,
   1608 	}
   1609 
   1610 	src2 := minio.CopySrcOptions{
   1611 		Bucket:    bucketName,
   1612 		Object:    objectName,
   1613 		VersionID: results[1].VersionID,
   1614 	}
   1615 
   1616 	dst := minio.CopyDestOptions{
   1617 		Bucket: bucketName,
   1618 		Object: objectName + "-copy",
   1619 	}
   1620 
   1621 	_, err = c.ComposeObject(context.Background(), dst, src1, src2)
   1622 	if err != nil {
   1623 		logError(testName, function, args, startTime, "", "ComposeObject failed", err)
   1624 		return
   1625 	}
   1626 
   1627 	// Destination object
   1628 	readerCopy, err := c.GetObject(context.Background(), bucketName, objectName+"-copy", minio.GetObjectOptions{})
   1629 	if err != nil {
   1630 		logError(testName, function, args, startTime, "", "GetObject of the copy object failed", err)
   1631 		return
   1632 	}
   1633 	defer readerCopy.Close()
   1634 
   1635 	copyContentBytes, err := io.ReadAll(readerCopy)
   1636 	if err != nil {
   1637 		logError(testName, function, args, startTime, "", "Reading from the copy object reader failed", err)
   1638 		return
   1639 	}
   1640 
   1641 	var expectedContent []byte
   1642 	for _, fileBytes := range testFilesBytes {
   1643 		expectedContent = append(expectedContent, fileBytes...)
   1644 	}
   1645 
   1646 	if len(copyContentBytes) == 0 || !bytes.Equal(copyContentBytes, expectedContent) {
   1647 		logError(testName, function, args, startTime, "", "Unexpected destination object content", err)
   1648 		return
   1649 	}
   1650 
   1651 	// Delete all objects and their versions as long as the bucket itself
   1652 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   1653 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1654 		return
   1655 	}
   1656 
   1657 	successLogger(testName, function, args, startTime).Info()
   1658 }
   1659 
   1660 func testRemoveObjectWithVersioning() {
   1661 	// initialize logging params
   1662 	startTime := time.Now()
   1663 	testName := getFuncName()
   1664 	function := "DeleteObject()"
   1665 	args := map[string]interface{}{}
   1666 
   1667 	// Seed random based on current time.
   1668 	rand.Seed(time.Now().Unix())
   1669 
   1670 	// Instantiate new minio client object.
   1671 	c, err := minio.New(os.Getenv(serverEndpoint),
   1672 		&minio.Options{
   1673 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1674 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1675 		})
   1676 	if err != nil {
   1677 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1678 		return
   1679 	}
   1680 
   1681 	// Enable tracing, write to stderr.
   1682 	// c.TraceOn(os.Stderr)
   1683 
   1684 	// Set user agent.
   1685 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1686 
   1687 	// Generate a new random bucket name.
   1688 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1689 	args["bucketName"] = bucketName
   1690 
   1691 	// Make a new bucket.
   1692 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1693 	if err != nil {
   1694 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1695 		return
   1696 	}
   1697 
   1698 	err = c.EnableVersioning(context.Background(), bucketName)
   1699 	if err != nil {
   1700 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1701 		return
   1702 	}
   1703 
   1704 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1705 	args["objectName"] = objectName
   1706 
   1707 	_, err = c.PutObject(context.Background(), bucketName, objectName, getDataReader("datafile-10-kB"), int64(dataFileMap["datafile-10-kB"]), minio.PutObjectOptions{})
   1708 	if err != nil {
   1709 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   1710 		return
   1711 	}
   1712 
   1713 	objectsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1714 	var version minio.ObjectInfo
   1715 	for info := range objectsInfo {
   1716 		if info.Err != nil {
   1717 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1718 			return
   1719 		}
   1720 		version = info
   1721 		break
   1722 	}
   1723 
   1724 	err = c.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{VersionID: version.VersionID})
   1725 	if err != nil {
   1726 		logError(testName, function, args, startTime, "", "DeleteObject failed", err)
   1727 		return
   1728 	}
   1729 
   1730 	objectsInfo = c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1731 	for range objectsInfo {
   1732 		logError(testName, function, args, startTime, "", "Unexpected versioning info, should not have any one ", err)
   1733 		return
   1734 	}
   1735 	// test delete marker version id is non-null
   1736 	_, err = c.PutObject(context.Background(), bucketName, objectName, getDataReader("datafile-10-kB"), int64(dataFileMap["datafile-10-kB"]), minio.PutObjectOptions{})
   1737 	if err != nil {
   1738 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   1739 		return
   1740 	}
   1741 	// create delete marker
   1742 	err = c.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
   1743 	if err != nil {
   1744 		logError(testName, function, args, startTime, "", "DeleteObject failed", err)
   1745 		return
   1746 	}
   1747 	objectsInfo = c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1748 	idx := 0
   1749 	for info := range objectsInfo {
   1750 		if info.Err != nil {
   1751 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1752 			return
   1753 		}
   1754 		if idx == 0 {
   1755 			if !info.IsDeleteMarker {
   1756 				logError(testName, function, args, startTime, "", "Unexpected error - expected delete marker to have been created", err)
   1757 				return
   1758 			}
   1759 			if info.VersionID == "" {
   1760 				logError(testName, function, args, startTime, "", "Unexpected error - expected delete marker to be versioned", err)
   1761 				return
   1762 			}
   1763 		}
   1764 		idx++
   1765 	}
   1766 
   1767 	defer cleanupBucket(bucketName, c)
   1768 
   1769 	successLogger(testName, function, args, startTime).Info()
   1770 }
   1771 
   1772 func testRemoveObjectsWithVersioning() {
   1773 	// initialize logging params
   1774 	startTime := time.Now()
   1775 	testName := getFuncName()
   1776 	function := "DeleteObjects()"
   1777 	args := map[string]interface{}{}
   1778 
   1779 	// Seed random based on current time.
   1780 	rand.Seed(time.Now().Unix())
   1781 
   1782 	// Instantiate new minio client object.
   1783 	c, err := minio.New(os.Getenv(serverEndpoint),
   1784 		&minio.Options{
   1785 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1786 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1787 		})
   1788 	if err != nil {
   1789 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1790 		return
   1791 	}
   1792 
   1793 	// Enable tracing, write to stderr.
   1794 	// c.TraceOn(os.Stderr)
   1795 
   1796 	// Set user agent.
   1797 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1798 
   1799 	// Generate a new random bucket name.
   1800 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1801 	args["bucketName"] = bucketName
   1802 
   1803 	// Make a new bucket.
   1804 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1805 	if err != nil {
   1806 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1807 		return
   1808 	}
   1809 
   1810 	err = c.EnableVersioning(context.Background(), bucketName)
   1811 	if err != nil {
   1812 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1813 		return
   1814 	}
   1815 
   1816 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1817 	args["objectName"] = objectName
   1818 
   1819 	_, err = c.PutObject(context.Background(), bucketName, objectName, getDataReader("datafile-10-kB"), int64(dataFileMap["datafile-10-kB"]), minio.PutObjectOptions{})
   1820 	if err != nil {
   1821 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   1822 		return
   1823 	}
   1824 
   1825 	objectsVersions := make(chan minio.ObjectInfo)
   1826 	go func() {
   1827 		objectsVersionsInfo := c.ListObjects(context.Background(), bucketName,
   1828 			minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1829 		for info := range objectsVersionsInfo {
   1830 			if info.Err != nil {
   1831 				logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1832 				return
   1833 			}
   1834 			objectsVersions <- info
   1835 		}
   1836 		close(objectsVersions)
   1837 	}()
   1838 
   1839 	removeErrors := c.RemoveObjects(context.Background(), bucketName, objectsVersions, minio.RemoveObjectsOptions{})
   1840 	if err != nil {
   1841 		logError(testName, function, args, startTime, "", "DeleteObjects call failed", err)
   1842 		return
   1843 	}
   1844 
   1845 	for e := range removeErrors {
   1846 		if e.Err != nil {
   1847 			logError(testName, function, args, startTime, "", "Single delete operation failed", err)
   1848 			return
   1849 		}
   1850 	}
   1851 
   1852 	objectsVersionsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1853 	for range objectsVersionsInfo {
   1854 		logError(testName, function, args, startTime, "", "Unexpected versioning info, should not have any one ", err)
   1855 		return
   1856 	}
   1857 
   1858 	err = c.RemoveBucket(context.Background(), bucketName)
   1859 	if err != nil {
   1860 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   1861 		return
   1862 	}
   1863 
   1864 	successLogger(testName, function, args, startTime).Info()
   1865 }
   1866 
   1867 func testObjectTaggingWithVersioning() {
   1868 	// initialize logging params
   1869 	startTime := time.Now()
   1870 	testName := getFuncName()
   1871 	function := "{Get,Set,Remove}ObjectTagging()"
   1872 	args := map[string]interface{}{}
   1873 
   1874 	// Seed random based on current time.
   1875 	rand.Seed(time.Now().Unix())
   1876 
   1877 	// Instantiate new minio client object.
   1878 	c, err := minio.New(os.Getenv(serverEndpoint),
   1879 		&minio.Options{
   1880 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   1881 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   1882 		})
   1883 	if err != nil {
   1884 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   1885 		return
   1886 	}
   1887 
   1888 	// Enable tracing, write to stderr.
   1889 	// c.TraceOn(os.Stderr)
   1890 
   1891 	// Set user agent.
   1892 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   1893 
   1894 	// Generate a new random bucket name.
   1895 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   1896 	args["bucketName"] = bucketName
   1897 
   1898 	// Make a new bucket.
   1899 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   1900 	if err != nil {
   1901 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   1902 		return
   1903 	}
   1904 
   1905 	err = c.EnableVersioning(context.Background(), bucketName)
   1906 	if err != nil {
   1907 		logError(testName, function, args, startTime, "", "Enable versioning failed", err)
   1908 		return
   1909 	}
   1910 
   1911 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   1912 	args["objectName"] = objectName
   1913 
   1914 	for _, file := range []string{"datafile-1-b", "datafile-10-kB"} {
   1915 		_, err = c.PutObject(context.Background(), bucketName, objectName, getDataReader(file), int64(dataFileMap[file]), minio.PutObjectOptions{})
   1916 		if err != nil {
   1917 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   1918 			return
   1919 		}
   1920 	}
   1921 
   1922 	versionsInfo := c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{WithVersions: true, Recursive: true})
   1923 
   1924 	var versions []minio.ObjectInfo
   1925 	for info := range versionsInfo {
   1926 		if info.Err != nil {
   1927 			logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
   1928 			return
   1929 		}
   1930 		versions = append(versions, info)
   1931 	}
   1932 
   1933 	sort.SliceStable(versions, func(i, j int) bool {
   1934 		return versions[i].Size < versions[j].Size
   1935 	})
   1936 
   1937 	tagsV1 := map[string]string{"key1": "val1"}
   1938 	t1, err := tags.MapToObjectTags(tagsV1)
   1939 	if err != nil {
   1940 		logError(testName, function, args, startTime, "", "PutObjectTagging (1) failed", err)
   1941 		return
   1942 	}
   1943 
   1944 	err = c.PutObjectTagging(context.Background(), bucketName, objectName, t1, minio.PutObjectTaggingOptions{VersionID: versions[0].VersionID})
   1945 	if err != nil {
   1946 		logError(testName, function, args, startTime, "", "PutObjectTagging (1) failed", err)
   1947 		return
   1948 	}
   1949 
   1950 	tagsV2 := map[string]string{"key2": "val2"}
   1951 	t2, err := tags.MapToObjectTags(tagsV2)
   1952 	if err != nil {
   1953 		logError(testName, function, args, startTime, "", "PutObjectTagging (1) failed", err)
   1954 		return
   1955 	}
   1956 
   1957 	err = c.PutObjectTagging(context.Background(), bucketName, objectName, t2, minio.PutObjectTaggingOptions{VersionID: versions[1].VersionID})
   1958 	if err != nil {
   1959 		logError(testName, function, args, startTime, "", "PutObjectTagging (2) failed", err)
   1960 		return
   1961 	}
   1962 
   1963 	tagsEqual := func(tags1, tags2 map[string]string) bool {
   1964 		for k1, v1 := range tags1 {
   1965 			v2, found := tags2[k1]
   1966 			if found {
   1967 				if v1 != v2 {
   1968 					return false
   1969 				}
   1970 			}
   1971 		}
   1972 		return true
   1973 	}
   1974 
   1975 	gotTagsV1, err := c.GetObjectTagging(context.Background(), bucketName, objectName, minio.GetObjectTaggingOptions{VersionID: versions[0].VersionID})
   1976 	if err != nil {
   1977 		logError(testName, function, args, startTime, "", "GetObjectTagging failed", err)
   1978 		return
   1979 	}
   1980 
   1981 	if !tagsEqual(t1.ToMap(), gotTagsV1.ToMap()) {
   1982 		logError(testName, function, args, startTime, "", "Unexpected tags content (1)", err)
   1983 		return
   1984 	}
   1985 
   1986 	gotTagsV2, err := c.GetObjectTagging(context.Background(), bucketName, objectName, minio.GetObjectTaggingOptions{})
   1987 	if err != nil {
   1988 		logError(testName, function, args, startTime, "", "GetObjectTaggingContext failed", err)
   1989 		return
   1990 	}
   1991 
   1992 	if !tagsEqual(t2.ToMap(), gotTagsV2.ToMap()) {
   1993 		logError(testName, function, args, startTime, "", "Unexpected tags content (2)", err)
   1994 		return
   1995 	}
   1996 
   1997 	err = c.RemoveObjectTagging(context.Background(), bucketName, objectName, minio.RemoveObjectTaggingOptions{VersionID: versions[0].VersionID})
   1998 	if err != nil {
   1999 		logError(testName, function, args, startTime, "", "PutObjectTagging (2) failed", err)
   2000 		return
   2001 	}
   2002 
   2003 	emptyTags, err := c.GetObjectTagging(context.Background(), bucketName, objectName,
   2004 		minio.GetObjectTaggingOptions{VersionID: versions[0].VersionID})
   2005 	if err != nil {
   2006 		logError(testName, function, args, startTime, "", "GetObjectTagging failed", err)
   2007 		return
   2008 	}
   2009 
   2010 	if len(emptyTags.ToMap()) != 0 {
   2011 		logError(testName, function, args, startTime, "", "Unexpected tags content (2)", err)
   2012 		return
   2013 	}
   2014 
   2015 	// Delete all objects and their versions as long as the bucket itself
   2016 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
   2017 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   2018 		return
   2019 	}
   2020 
   2021 	successLogger(testName, function, args, startTime).Info()
   2022 }
   2023 
   2024 // Test PutObject with custom checksums.
   2025 func testPutObjectWithChecksums() {
   2026 	// initialize logging params
   2027 	startTime := time.Now()
   2028 	testName := getFuncName()
   2029 	function := "PutObject(bucketName, objectName, reader,size, opts)"
   2030 	args := map[string]interface{}{
   2031 		"bucketName": "",
   2032 		"objectName": "",
   2033 		"opts":       "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
   2034 	}
   2035 
   2036 	if !isFullMode() {
   2037 		ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
   2038 		return
   2039 	}
   2040 
   2041 	// Seed random based on current time.
   2042 	rand.Seed(time.Now().Unix())
   2043 
   2044 	// Instantiate new minio client object.
   2045 	c, err := minio.New(os.Getenv(serverEndpoint),
   2046 		&minio.Options{
   2047 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2048 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   2049 		})
   2050 	if err != nil {
   2051 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2052 		return
   2053 	}
   2054 
   2055 	// Enable tracing, write to stderr.
   2056 	// c.TraceOn(os.Stderr)
   2057 
   2058 	// Set user agent.
   2059 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2060 
   2061 	// Generate a new random bucket name.
   2062 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2063 	args["bucketName"] = bucketName
   2064 
   2065 	// Make a new bucket.
   2066 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2067 	if err != nil {
   2068 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   2069 		return
   2070 	}
   2071 
   2072 	defer cleanupBucket(bucketName, c)
   2073 	tests := []struct {
   2074 		header string
   2075 		hasher hash.Hash
   2076 
   2077 		// Checksum values
   2078 		ChecksumCRC32  string
   2079 		ChecksumCRC32C string
   2080 		ChecksumSHA1   string
   2081 		ChecksumSHA256 string
   2082 	}{
   2083 		{header: "x-amz-checksum-crc32", hasher: crc32.NewIEEE()},
   2084 		{header: "x-amz-checksum-crc32c", hasher: crc32.New(crc32.MakeTable(crc32.Castagnoli))},
   2085 		{header: "x-amz-checksum-sha1", hasher: sha1.New()},
   2086 		{header: "x-amz-checksum-sha256", hasher: sha256.New()},
   2087 	}
   2088 
   2089 	for i, test := range tests {
   2090 		bufSize := dataFileMap["datafile-10-kB"]
   2091 
   2092 		// Save the data
   2093 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   2094 		args["objectName"] = objectName
   2095 
   2096 		cmpChecksum := func(got, want string) {
   2097 			if want != got {
   2098 				logError(testName, function, args, startTime, "", "checksum mismatch", fmt.Errorf("want %s, got %s", want, got))
   2099 				return
   2100 			}
   2101 		}
   2102 
   2103 		meta := map[string]string{}
   2104 		reader := getDataReader("datafile-10-kB")
   2105 		b, err := io.ReadAll(reader)
   2106 		if err != nil {
   2107 			logError(testName, function, args, startTime, "", "Read failed", err)
   2108 			return
   2109 		}
   2110 		h := test.hasher
   2111 		h.Reset()
   2112 		// Wrong CRC.
   2113 		meta[test.header] = base64.StdEncoding.EncodeToString(h.Sum(nil))
   2114 		args["metadata"] = meta
   2115 		args["range"] = "false"
   2116 
   2117 		resp, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), minio.PutObjectOptions{
   2118 			DisableMultipart: true,
   2119 			UserMetadata:     meta,
   2120 		})
   2121 		if err == nil {
   2122 			if i == 0 && resp.ChecksumCRC32 == "" {
   2123 				ignoredLog(testName, function, args, startTime, "Checksums does not appear to be supported by backend").Info()
   2124 				return
   2125 			}
   2126 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2127 			return
   2128 		}
   2129 
   2130 		// Set correct CRC.
   2131 		h.Write(b)
   2132 		meta[test.header] = base64.StdEncoding.EncodeToString(h.Sum(nil))
   2133 		reader.Close()
   2134 
   2135 		resp, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), minio.PutObjectOptions{
   2136 			DisableMultipart:     true,
   2137 			DisableContentSha256: true,
   2138 			UserMetadata:         meta,
   2139 		})
   2140 		if err != nil {
   2141 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2142 			return
   2143 		}
   2144 		cmpChecksum(resp.ChecksumSHA256, meta["x-amz-checksum-sha256"])
   2145 		cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
   2146 		cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
   2147 		cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
   2148 
   2149 		// Read the data back
   2150 		gopts := minio.GetObjectOptions{Checksum: true}
   2151 
   2152 		r, err := c.GetObject(context.Background(), bucketName, objectName, gopts)
   2153 		if err != nil {
   2154 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   2155 			return
   2156 		}
   2157 
   2158 		st, err := r.Stat()
   2159 		if err != nil {
   2160 			logError(testName, function, args, startTime, "", "Stat failed", err)
   2161 			return
   2162 		}
   2163 		cmpChecksum(st.ChecksumSHA256, meta["x-amz-checksum-sha256"])
   2164 		cmpChecksum(st.ChecksumSHA1, meta["x-amz-checksum-sha1"])
   2165 		cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
   2166 		cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
   2167 
   2168 		if st.Size != int64(bufSize) {
   2169 			logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
   2170 			return
   2171 		}
   2172 
   2173 		if err := r.Close(); err != nil {
   2174 			logError(testName, function, args, startTime, "", "Object Close failed", err)
   2175 			return
   2176 		}
   2177 		if err := r.Close(); err == nil {
   2178 			logError(testName, function, args, startTime, "", "Object already closed, should respond with error", err)
   2179 			return
   2180 		}
   2181 
   2182 		args["range"] = "true"
   2183 		err = gopts.SetRange(100, 1000)
   2184 		if err != nil {
   2185 			logError(testName, function, args, startTime, "", "SetRange failed", err)
   2186 			return
   2187 		}
   2188 		r, err = c.GetObject(context.Background(), bucketName, objectName, gopts)
   2189 		if err != nil {
   2190 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   2191 			return
   2192 		}
   2193 
   2194 		b, err = io.ReadAll(r)
   2195 		if err != nil {
   2196 			logError(testName, function, args, startTime, "", "Read failed", err)
   2197 			return
   2198 		}
   2199 		st, err = r.Stat()
   2200 		if err != nil {
   2201 			logError(testName, function, args, startTime, "", "Stat failed", err)
   2202 			return
   2203 		}
   2204 
   2205 		// Range requests should return empty checksums...
   2206 		cmpChecksum(st.ChecksumSHA256, "")
   2207 		cmpChecksum(st.ChecksumSHA1, "")
   2208 		cmpChecksum(st.ChecksumCRC32, "")
   2209 		cmpChecksum(st.ChecksumCRC32C, "")
   2210 
   2211 		delete(args, "range")
   2212 		delete(args, "metadata")
   2213 	}
   2214 
   2215 	successLogger(testName, function, args, startTime).Info()
   2216 }
   2217 
   2218 // Test PutObject with custom checksums.
   2219 func testPutMultipartObjectWithChecksums() {
   2220 	// initialize logging params
   2221 	startTime := time.Now()
   2222 	testName := getFuncName()
   2223 	function := "PutObject(bucketName, objectName, reader,size, opts)"
   2224 	args := map[string]interface{}{
   2225 		"bucketName": "",
   2226 		"objectName": "",
   2227 		"opts":       "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
   2228 	}
   2229 
   2230 	if !isFullMode() {
   2231 		ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
   2232 		return
   2233 	}
   2234 
   2235 	// Seed random based on current time.
   2236 	rand.Seed(time.Now().Unix())
   2237 
   2238 	// Instantiate new minio client object.
   2239 	c, err := minio.New(os.Getenv(serverEndpoint),
   2240 		&minio.Options{
   2241 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2242 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   2243 		})
   2244 	if err != nil {
   2245 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2246 		return
   2247 	}
   2248 
   2249 	// Enable tracing, write to stderr.
   2250 	// c.TraceOn(os.Stderr)
   2251 
   2252 	// Set user agent.
   2253 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2254 
   2255 	// Generate a new random bucket name.
   2256 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2257 	args["bucketName"] = bucketName
   2258 
   2259 	// Make a new bucket.
   2260 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2261 	if err != nil {
   2262 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   2263 		return
   2264 	}
   2265 
   2266 	hashMultiPart := func(b []byte, partSize int, hasher hash.Hash) string {
   2267 		r := bytes.NewReader(b)
   2268 		tmp := make([]byte, partSize)
   2269 		parts := 0
   2270 		var all []byte
   2271 		for {
   2272 			n, err := io.ReadFull(r, tmp)
   2273 			if err != nil && err != io.ErrUnexpectedEOF {
   2274 				logError(testName, function, args, startTime, "", "Calc crc failed", err)
   2275 			}
   2276 			if n == 0 {
   2277 				break
   2278 			}
   2279 			parts++
   2280 			hasher.Reset()
   2281 			hasher.Write(tmp[:n])
   2282 			all = append(all, hasher.Sum(nil)...)
   2283 			if err != nil {
   2284 				break
   2285 			}
   2286 		}
   2287 		hasher.Reset()
   2288 		hasher.Write(all)
   2289 		return fmt.Sprintf("%s-%d", base64.StdEncoding.EncodeToString(hasher.Sum(nil)), parts)
   2290 	}
   2291 	defer cleanupBucket(bucketName, c)
   2292 	tests := []struct {
   2293 		header string
   2294 		hasher hash.Hash
   2295 
   2296 		// Checksum values
   2297 		ChecksumCRC32  string
   2298 		ChecksumCRC32C string
   2299 		ChecksumSHA1   string
   2300 		ChecksumSHA256 string
   2301 	}{
   2302 		// Currently there is no way to override the checksum type.
   2303 		{header: "x-amz-checksum-crc32c", hasher: crc32.New(crc32.MakeTable(crc32.Castagnoli)), ChecksumCRC32C: "OpEx0Q==-13"},
   2304 	}
   2305 
   2306 	for _, test := range tests {
   2307 		bufSize := dataFileMap["datafile-129-MB"]
   2308 
   2309 		// Save the data
   2310 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   2311 		args["objectName"] = objectName
   2312 
   2313 		cmpChecksum := func(got, want string) {
   2314 			if want != got {
   2315 				// logError(testName, function, args, startTime, "", "checksum mismatch", fmt.Errorf("want %s, got %s", want, got))
   2316 				fmt.Printf("want %s, got %s\n", want, got)
   2317 				return
   2318 			}
   2319 		}
   2320 
   2321 		const partSize = 10 << 20
   2322 		reader := getDataReader("datafile-129-MB")
   2323 		b, err := io.ReadAll(reader)
   2324 		if err != nil {
   2325 			logError(testName, function, args, startTime, "", "Read failed", err)
   2326 			return
   2327 		}
   2328 		reader.Close()
   2329 		h := test.hasher
   2330 		h.Reset()
   2331 		test.ChecksumCRC32C = hashMultiPart(b, partSize, test.hasher)
   2332 
   2333 		// Set correct CRC.
   2334 
   2335 		resp, err := c.PutObject(context.Background(), bucketName, objectName, io.NopCloser(bytes.NewReader(b)), int64(bufSize), minio.PutObjectOptions{
   2336 			DisableContentSha256: true,
   2337 			DisableMultipart:     false,
   2338 			UserMetadata:         nil,
   2339 			PartSize:             partSize,
   2340 		})
   2341 		if err != nil {
   2342 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2343 			return
   2344 		}
   2345 		cmpChecksum(resp.ChecksumSHA256, test.ChecksumSHA256)
   2346 		cmpChecksum(resp.ChecksumSHA1, test.ChecksumSHA1)
   2347 		cmpChecksum(resp.ChecksumCRC32, test.ChecksumCRC32)
   2348 		cmpChecksum(resp.ChecksumCRC32C, test.ChecksumCRC32C)
   2349 
   2350 		// Read the data back
   2351 		gopts := minio.GetObjectOptions{Checksum: true}
   2352 		gopts.PartNumber = 2
   2353 
   2354 		// We cannot use StatObject, since it ignores partnumber.
   2355 		r, err := c.GetObject(context.Background(), bucketName, objectName, gopts)
   2356 		if err != nil {
   2357 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   2358 			return
   2359 		}
   2360 		io.Copy(io.Discard, r)
   2361 		st, err := r.Stat()
   2362 		if err != nil {
   2363 			logError(testName, function, args, startTime, "", "Stat failed", err)
   2364 			return
   2365 		}
   2366 
   2367 		// Test part 2 checksum...
   2368 		h.Reset()
   2369 		h.Write(b[partSize : 2*partSize])
   2370 		got := base64.StdEncoding.EncodeToString(h.Sum(nil))
   2371 		if test.ChecksumSHA256 != "" {
   2372 			cmpChecksum(st.ChecksumSHA256, got)
   2373 		}
   2374 		if test.ChecksumSHA1 != "" {
   2375 			cmpChecksum(st.ChecksumSHA1, got)
   2376 		}
   2377 		if test.ChecksumCRC32 != "" {
   2378 			cmpChecksum(st.ChecksumCRC32, got)
   2379 		}
   2380 		if test.ChecksumCRC32C != "" {
   2381 			cmpChecksum(st.ChecksumCRC32C, got)
   2382 		}
   2383 
   2384 		delete(args, "metadata")
   2385 	}
   2386 
   2387 	successLogger(testName, function, args, startTime).Info()
   2388 }
   2389 
   2390 // Test PutObject with trailing checksums.
   2391 func testTrailingChecksums() {
   2392 	// initialize logging params
   2393 	startTime := time.Now()
   2394 	testName := getFuncName()
   2395 	function := "PutObject(bucketName, objectName, reader,size, opts)"
   2396 	args := map[string]interface{}{
   2397 		"bucketName": "",
   2398 		"objectName": "",
   2399 		"opts":       "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
   2400 	}
   2401 
   2402 	if !isFullMode() {
   2403 		ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
   2404 		return
   2405 	}
   2406 
   2407 	// Instantiate new minio client object.
   2408 	c, err := minio.New(os.Getenv(serverEndpoint),
   2409 		&minio.Options{
   2410 			Creds:           credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2411 			Secure:          mustParseBool(os.Getenv(enableHTTPS)),
   2412 			TrailingHeaders: true,
   2413 		})
   2414 	if err != nil {
   2415 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2416 		return
   2417 	}
   2418 
   2419 	// Enable tracing, write to stderr.
   2420 	// c.TraceOn(os.Stderr)
   2421 
   2422 	// Set user agent.
   2423 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2424 
   2425 	// Generate a new random bucket name.
   2426 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2427 	args["bucketName"] = bucketName
   2428 
   2429 	// Make a new bucket.
   2430 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2431 	if err != nil {
   2432 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   2433 		return
   2434 	}
   2435 
   2436 	hashMultiPart := func(b []byte, partSize int, hasher hash.Hash) string {
   2437 		r := bytes.NewReader(b)
   2438 		tmp := make([]byte, partSize)
   2439 		parts := 0
   2440 		var all []byte
   2441 		for {
   2442 			n, err := io.ReadFull(r, tmp)
   2443 			if err != nil && err != io.ErrUnexpectedEOF {
   2444 				logError(testName, function, args, startTime, "", "Calc crc failed", err)
   2445 			}
   2446 			if n == 0 {
   2447 				break
   2448 			}
   2449 			parts++
   2450 			hasher.Reset()
   2451 			hasher.Write(tmp[:n])
   2452 			all = append(all, hasher.Sum(nil)...)
   2453 			if err != nil {
   2454 				break
   2455 			}
   2456 		}
   2457 		hasher.Reset()
   2458 		hasher.Write(all)
   2459 		return fmt.Sprintf("%s-%d", base64.StdEncoding.EncodeToString(hasher.Sum(nil)), parts)
   2460 	}
   2461 	defer cleanupBucket(bucketName, c)
   2462 	tests := []struct {
   2463 		header string
   2464 		hasher hash.Hash
   2465 
   2466 		// Checksum values
   2467 		ChecksumCRC32  string
   2468 		ChecksumCRC32C string
   2469 		ChecksumSHA1   string
   2470 		ChecksumSHA256 string
   2471 		PO             minio.PutObjectOptions
   2472 	}{
   2473 		// Currently there is no way to override the checksum type.
   2474 		{header: "x-amz-checksum-crc32c",
   2475 			hasher:         crc32.New(crc32.MakeTable(crc32.Castagnoli)),
   2476 			ChecksumCRC32C: "set",
   2477 			PO: minio.PutObjectOptions{
   2478 				DisableContentSha256: true,
   2479 				DisableMultipart:     false,
   2480 				UserMetadata:         nil,
   2481 				PartSize:             5 << 20,
   2482 			},
   2483 		},
   2484 		{header: "x-amz-checksum-crc32c",
   2485 			hasher:         crc32.New(crc32.MakeTable(crc32.Castagnoli)),
   2486 			ChecksumCRC32C: "set",
   2487 			PO: minio.PutObjectOptions{
   2488 				DisableContentSha256: true,
   2489 				DisableMultipart:     false,
   2490 				UserMetadata:         nil,
   2491 				PartSize:             6_645_654, // Rather arbitrary size
   2492 			},
   2493 		},
   2494 		{header: "x-amz-checksum-crc32c",
   2495 			hasher:         crc32.New(crc32.MakeTable(crc32.Castagnoli)),
   2496 			ChecksumCRC32C: "set",
   2497 			PO: minio.PutObjectOptions{
   2498 				DisableContentSha256: false,
   2499 				DisableMultipart:     false,
   2500 				UserMetadata:         nil,
   2501 				PartSize:             5 << 20,
   2502 			},
   2503 		},
   2504 		{header: "x-amz-checksum-crc32c",
   2505 			hasher:         crc32.New(crc32.MakeTable(crc32.Castagnoli)),
   2506 			ChecksumCRC32C: "set",
   2507 			PO: minio.PutObjectOptions{
   2508 				DisableContentSha256: false,
   2509 				DisableMultipart:     false,
   2510 				UserMetadata:         nil,
   2511 				PartSize:             6_645_654, // Rather arbitrary size
   2512 			},
   2513 		},
   2514 	}
   2515 
   2516 	for _, test := range tests {
   2517 		bufSize := dataFileMap["datafile-11-MB"]
   2518 
   2519 		// Save the data
   2520 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   2521 		args["objectName"] = objectName
   2522 
   2523 		cmpChecksum := func(got, want string) {
   2524 			if want != got {
   2525 				logError(testName, function, args, startTime, "", "checksum mismatch", fmt.Errorf("want %q, got %q", want, got))
   2526 				return
   2527 			}
   2528 		}
   2529 
   2530 		reader := getDataReader("datafile-11-MB")
   2531 		b, err := io.ReadAll(reader)
   2532 		if err != nil {
   2533 			logError(testName, function, args, startTime, "", "Read failed", err)
   2534 			return
   2535 		}
   2536 		reader.Close()
   2537 		h := test.hasher
   2538 		h.Reset()
   2539 		test.ChecksumCRC32C = hashMultiPart(b, int(test.PO.PartSize), test.hasher)
   2540 
   2541 		// Set correct CRC.
   2542 		// c.TraceOn(os.Stderr)
   2543 		resp, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), test.PO)
   2544 		if err != nil {
   2545 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2546 			return
   2547 		}
   2548 		// c.TraceOff()
   2549 		cmpChecksum(resp.ChecksumSHA256, test.ChecksumSHA256)
   2550 		cmpChecksum(resp.ChecksumSHA1, test.ChecksumSHA1)
   2551 		cmpChecksum(resp.ChecksumCRC32, test.ChecksumCRC32)
   2552 		cmpChecksum(resp.ChecksumCRC32C, test.ChecksumCRC32C)
   2553 
   2554 		// Read the data back
   2555 		gopts := minio.GetObjectOptions{Checksum: true}
   2556 		gopts.PartNumber = 2
   2557 
   2558 		// We cannot use StatObject, since it ignores partnumber.
   2559 		r, err := c.GetObject(context.Background(), bucketName, objectName, gopts)
   2560 		if err != nil {
   2561 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   2562 			return
   2563 		}
   2564 		io.Copy(io.Discard, r)
   2565 		st, err := r.Stat()
   2566 		if err != nil {
   2567 			logError(testName, function, args, startTime, "", "Stat failed", err)
   2568 			return
   2569 		}
   2570 
   2571 		// Test part 2 checksum...
   2572 		h.Reset()
   2573 		p2 := b[test.PO.PartSize:]
   2574 		if len(p2) > int(test.PO.PartSize) {
   2575 			p2 = p2[:test.PO.PartSize]
   2576 		}
   2577 		h.Write(p2)
   2578 		got := base64.StdEncoding.EncodeToString(h.Sum(nil))
   2579 		if test.ChecksumSHA256 != "" {
   2580 			cmpChecksum(st.ChecksumSHA256, got)
   2581 		}
   2582 		if test.ChecksumSHA1 != "" {
   2583 			cmpChecksum(st.ChecksumSHA1, got)
   2584 		}
   2585 		if test.ChecksumCRC32 != "" {
   2586 			cmpChecksum(st.ChecksumCRC32, got)
   2587 		}
   2588 		if test.ChecksumCRC32C != "" {
   2589 			cmpChecksum(st.ChecksumCRC32C, got)
   2590 		}
   2591 
   2592 		delete(args, "metadata")
   2593 	}
   2594 }
   2595 
   2596 // Test PutObject with custom checksums.
   2597 func testPutObjectWithAutomaticChecksums() {
   2598 	// initialize logging params
   2599 	startTime := time.Now()
   2600 	testName := getFuncName()
   2601 	function := "PutObject(bucketName, objectName, reader,size, opts)"
   2602 	args := map[string]interface{}{
   2603 		"bucketName": "",
   2604 		"objectName": "",
   2605 		"opts":       "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
   2606 	}
   2607 
   2608 	if !isFullMode() {
   2609 		ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
   2610 		return
   2611 	}
   2612 
   2613 	// Seed random based on current time.
   2614 	rand.Seed(time.Now().Unix())
   2615 
   2616 	// Instantiate new minio client object.
   2617 	c, err := minio.New(os.Getenv(serverEndpoint),
   2618 		&minio.Options{
   2619 			Creds:           credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2620 			Secure:          mustParseBool(os.Getenv(enableHTTPS)),
   2621 			TrailingHeaders: true,
   2622 		})
   2623 	if err != nil {
   2624 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2625 		return
   2626 	}
   2627 
   2628 	// Set user agent.
   2629 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2630 
   2631 	// Generate a new random bucket name.
   2632 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2633 	args["bucketName"] = bucketName
   2634 
   2635 	// Make a new bucket.
   2636 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2637 	if err != nil {
   2638 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   2639 		return
   2640 	}
   2641 
   2642 	defer cleanupBucket(bucketName, c)
   2643 	tests := []struct {
   2644 		header string
   2645 		hasher hash.Hash
   2646 
   2647 		// Checksum values
   2648 		ChecksumCRC32  string
   2649 		ChecksumCRC32C string
   2650 		ChecksumSHA1   string
   2651 		ChecksumSHA256 string
   2652 	}{
   2653 		// Built-in will only add crc32c, when no MD5 nor SHA256.
   2654 		{header: "x-amz-checksum-crc32c", hasher: crc32.New(crc32.MakeTable(crc32.Castagnoli))},
   2655 	}
   2656 
   2657 	// Enable tracing, write to stderr.
   2658 	// c.TraceOn(os.Stderr)
   2659 	// defer c.TraceOff()
   2660 
   2661 	for i, test := range tests {
   2662 		bufSize := dataFileMap["datafile-10-kB"]
   2663 
   2664 		// Save the data
   2665 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   2666 		args["objectName"] = objectName
   2667 
   2668 		cmpChecksum := func(got, want string) {
   2669 			if want != got {
   2670 				logError(testName, function, args, startTime, "", "checksum mismatch", fmt.Errorf("want %s, got %s", want, got))
   2671 				return
   2672 			}
   2673 		}
   2674 
   2675 		meta := map[string]string{}
   2676 		reader := getDataReader("datafile-10-kB")
   2677 		b, err := io.ReadAll(reader)
   2678 		if err != nil {
   2679 			logError(testName, function, args, startTime, "", "Read failed", err)
   2680 			return
   2681 		}
   2682 
   2683 		h := test.hasher
   2684 		h.Reset()
   2685 		h.Write(b)
   2686 		meta[test.header] = base64.StdEncoding.EncodeToString(h.Sum(nil))
   2687 		args["metadata"] = meta
   2688 
   2689 		resp, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), minio.PutObjectOptions{
   2690 			DisableMultipart:     true,
   2691 			UserMetadata:         nil,
   2692 			DisableContentSha256: true,
   2693 			SendContentMd5:       false,
   2694 		})
   2695 		if err == nil {
   2696 			if i == 0 && resp.ChecksumCRC32C == "" {
   2697 				ignoredLog(testName, function, args, startTime, "Checksums does not appear to be supported by backend").Info()
   2698 				return
   2699 			}
   2700 		} else {
   2701 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2702 			return
   2703 		}
   2704 		cmpChecksum(resp.ChecksumSHA256, meta["x-amz-checksum-sha256"])
   2705 		cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
   2706 		cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
   2707 		cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
   2708 
   2709 		// Usually this will be the same as above, since we skip automatic checksum when SHA256 content is sent.
   2710 		// When/if we add a checksum control to PutObjectOptions this will make more sense.
   2711 		resp, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), minio.PutObjectOptions{
   2712 			DisableMultipart:     true,
   2713 			UserMetadata:         nil,
   2714 			DisableContentSha256: false,
   2715 			SendContentMd5:       false,
   2716 		})
   2717 		if err != nil {
   2718 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2719 			return
   2720 		}
   2721 		// The checksum will not be enabled on HTTP, since it uses SHA256 blocks.
   2722 		if mustParseBool(os.Getenv(enableHTTPS)) {
   2723 			cmpChecksum(resp.ChecksumSHA256, meta["x-amz-checksum-sha256"])
   2724 			cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
   2725 			cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
   2726 			cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
   2727 		}
   2728 
   2729 		// Set SHA256 header manually
   2730 		sh256 := sha256.Sum256(b)
   2731 		meta = map[string]string{"x-amz-checksum-sha256": base64.StdEncoding.EncodeToString(sh256[:])}
   2732 		args["metadata"] = meta
   2733 		resp, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(b), int64(bufSize), minio.PutObjectOptions{
   2734 			DisableMultipart:     true,
   2735 			UserMetadata:         meta,
   2736 			DisableContentSha256: true,
   2737 			SendContentMd5:       false,
   2738 		})
   2739 		if err != nil {
   2740 			logError(testName, function, args, startTime, "", "PutObject failed", err)
   2741 			return
   2742 		}
   2743 		cmpChecksum(resp.ChecksumSHA256, meta["x-amz-checksum-sha256"])
   2744 		cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
   2745 		cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
   2746 		cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
   2747 		delete(args, "metadata")
   2748 	}
   2749 
   2750 	successLogger(testName, function, args, startTime).Info()
   2751 }
   2752 
   2753 // Test PutObject using a large data to trigger multipart readat
   2754 func testPutObjectWithMetadata() {
   2755 	// initialize logging params
   2756 	startTime := time.Now()
   2757 	testName := getFuncName()
   2758 	function := "PutObject(bucketName, objectName, reader,size, opts)"
   2759 	args := map[string]interface{}{
   2760 		"bucketName": "",
   2761 		"objectName": "",
   2762 		"opts":       "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
   2763 	}
   2764 
   2765 	if !isFullMode() {
   2766 		ignoredLog(testName, function, args, startTime, "Skipping functional tests for short/quick runs").Info()
   2767 		return
   2768 	}
   2769 
   2770 	// Seed random based on current time.
   2771 	rand.Seed(time.Now().Unix())
   2772 
   2773 	// Instantiate new minio client object.
   2774 	c, err := minio.New(os.Getenv(serverEndpoint),
   2775 		&minio.Options{
   2776 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2777 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   2778 		})
   2779 	if err != nil {
   2780 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2781 		return
   2782 	}
   2783 
   2784 	// Enable tracing, write to stderr.
   2785 	// c.TraceOn(os.Stderr)
   2786 
   2787 	// Set user agent.
   2788 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2789 
   2790 	// Generate a new random bucket name.
   2791 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2792 	args["bucketName"] = bucketName
   2793 
   2794 	// Make a new bucket.
   2795 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2796 	if err != nil {
   2797 		logError(testName, function, args, startTime, "", "Make bucket failed", err)
   2798 		return
   2799 	}
   2800 
   2801 	defer cleanupBucket(bucketName, c)
   2802 
   2803 	bufSize := dataFileMap["datafile-129-MB"]
   2804 	reader := getDataReader("datafile-129-MB")
   2805 	defer reader.Close()
   2806 
   2807 	// Save the data
   2808 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   2809 	args["objectName"] = objectName
   2810 
   2811 	// Object custom metadata
   2812 	customContentType := "custom/contenttype"
   2813 
   2814 	args["metadata"] = map[string][]string{
   2815 		"Content-Type":         {customContentType},
   2816 		"X-Amz-Meta-CustomKey": {"extra  spaces  in   value"},
   2817 	}
   2818 
   2819 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{
   2820 		ContentType: customContentType,
   2821 	})
   2822 	if err != nil {
   2823 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   2824 		return
   2825 	}
   2826 
   2827 	// Read the data back
   2828 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   2829 	if err != nil {
   2830 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   2831 		return
   2832 	}
   2833 
   2834 	st, err := r.Stat()
   2835 	if err != nil {
   2836 		logError(testName, function, args, startTime, "", "Stat failed", err)
   2837 		return
   2838 	}
   2839 	if st.Size != int64(bufSize) {
   2840 		logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
   2841 		return
   2842 	}
   2843 	if st.ContentType != customContentType && st.ContentType != "application/octet-stream" {
   2844 		logError(testName, function, args, startTime, "", "ContentType does not match, expected "+customContentType+" got "+st.ContentType, err)
   2845 		return
   2846 	}
   2847 	if err := crcMatchesName(r, "datafile-129-MB"); err != nil {
   2848 		logError(testName, function, args, startTime, "", "data CRC check failed", err)
   2849 		return
   2850 	}
   2851 	if err := r.Close(); err != nil {
   2852 		logError(testName, function, args, startTime, "", "Object Close failed", err)
   2853 		return
   2854 	}
   2855 	if err := r.Close(); err == nil {
   2856 		logError(testName, function, args, startTime, "", "Object already closed, should respond with error", err)
   2857 		return
   2858 	}
   2859 
   2860 	successLogger(testName, function, args, startTime).Info()
   2861 }
   2862 
   2863 func testPutObjectWithContentLanguage() {
   2864 	// initialize logging params
   2865 	objectName := "test-object"
   2866 	startTime := time.Now()
   2867 	testName := getFuncName()
   2868 	function := "PutObject(bucketName, objectName, reader, size, opts)"
   2869 	args := map[string]interface{}{
   2870 		"bucketName": "",
   2871 		"objectName": objectName,
   2872 		"size":       -1,
   2873 		"opts":       "",
   2874 	}
   2875 
   2876 	// Seed random based on current time.
   2877 	rand.Seed(time.Now().Unix())
   2878 
   2879 	// Instantiate new minio client object.
   2880 	c, err := minio.New(os.Getenv(serverEndpoint),
   2881 		&minio.Options{
   2882 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2883 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   2884 		})
   2885 	if err != nil {
   2886 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2887 		return
   2888 	}
   2889 
   2890 	// Enable tracing, write to stderr.
   2891 	// c.TraceOn(os.Stderr)
   2892 
   2893 	// Set user agent.
   2894 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2895 
   2896 	// Generate a new random bucket name.
   2897 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2898 	args["bucketName"] = bucketName
   2899 	// Make a new bucket.
   2900 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2901 	if err != nil {
   2902 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   2903 		return
   2904 	}
   2905 
   2906 	defer cleanupBucket(bucketName, c)
   2907 
   2908 	data := []byte{}
   2909 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(data), int64(0), minio.PutObjectOptions{
   2910 		ContentLanguage: "en",
   2911 	})
   2912 	if err != nil {
   2913 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   2914 		return
   2915 	}
   2916 
   2917 	objInfo, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
   2918 	if err != nil {
   2919 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   2920 		return
   2921 	}
   2922 
   2923 	if objInfo.Metadata.Get("Content-Language") != "en" {
   2924 		logError(testName, function, args, startTime, "", "Expected content-language 'en' doesn't match with StatObject return value", err)
   2925 		return
   2926 	}
   2927 
   2928 	successLogger(testName, function, args, startTime).Info()
   2929 }
   2930 
   2931 // Test put object with streaming signature.
   2932 func testPutObjectStreaming() {
   2933 	// initialize logging params
   2934 	objectName := "test-object"
   2935 	startTime := time.Now()
   2936 	testName := getFuncName()
   2937 	function := "PutObject(bucketName, objectName, reader,size,opts)"
   2938 	args := map[string]interface{}{
   2939 		"bucketName": "",
   2940 		"objectName": objectName,
   2941 		"size":       -1,
   2942 		"opts":       "",
   2943 	}
   2944 
   2945 	// Seed random based on current time.
   2946 	rand.Seed(time.Now().Unix())
   2947 
   2948 	// Instantiate new minio client object.
   2949 	c, err := minio.New(os.Getenv(serverEndpoint),
   2950 		&minio.Options{
   2951 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   2952 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   2953 		})
   2954 	if err != nil {
   2955 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   2956 		return
   2957 	}
   2958 
   2959 	// Enable tracing, write to stderr.
   2960 	// c.TraceOn(os.Stderr)
   2961 
   2962 	// Set user agent.
   2963 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   2964 
   2965 	// Generate a new random bucket name.
   2966 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   2967 	args["bucketName"] = bucketName
   2968 	// Make a new bucket.
   2969 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   2970 	if err != nil {
   2971 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   2972 		return
   2973 	}
   2974 
   2975 	defer cleanupBucket(bucketName, c)
   2976 
   2977 	// Upload an object.
   2978 	sizes := []int64{0, 64*1024 - 1, 64 * 1024}
   2979 
   2980 	for _, size := range sizes {
   2981 		data := newRandomReader(size, size)
   2982 		ui, err := c.PutObject(context.Background(), bucketName, objectName, data, int64(size), minio.PutObjectOptions{})
   2983 		if err != nil {
   2984 			logError(testName, function, args, startTime, "", "PutObjectStreaming failed", err)
   2985 			return
   2986 		}
   2987 
   2988 		if ui.Size != size {
   2989 			logError(testName, function, args, startTime, "", "PutObjectStreaming result has unexpected size", nil)
   2990 			return
   2991 		}
   2992 
   2993 		objInfo, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
   2994 		if err != nil {
   2995 			logError(testName, function, args, startTime, "", "StatObject failed", err)
   2996 			return
   2997 		}
   2998 		if objInfo.Size != size {
   2999 			logError(testName, function, args, startTime, "", "Unexpected size", err)
   3000 			return
   3001 		}
   3002 
   3003 	}
   3004 
   3005 	successLogger(testName, function, args, startTime).Info()
   3006 }
   3007 
   3008 // Test get object seeker from the end, using whence set to '2'.
   3009 func testGetObjectSeekEnd() {
   3010 	// initialize logging params
   3011 	startTime := time.Now()
   3012 	testName := getFuncName()
   3013 	function := "GetObject(bucketName, objectName)"
   3014 	args := map[string]interface{}{}
   3015 
   3016 	// Seed random based on current time.
   3017 	rand.Seed(time.Now().Unix())
   3018 
   3019 	// Instantiate new minio client object.
   3020 	c, err := minio.New(os.Getenv(serverEndpoint),
   3021 		&minio.Options{
   3022 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3023 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3024 		})
   3025 	if err != nil {
   3026 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3027 		return
   3028 	}
   3029 
   3030 	// Enable tracing, write to stderr.
   3031 	// c.TraceOn(os.Stderr)
   3032 
   3033 	// Set user agent.
   3034 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3035 
   3036 	// Generate a new random bucket name.
   3037 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3038 	args["bucketName"] = bucketName
   3039 
   3040 	// Make a new bucket.
   3041 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3042 	if err != nil {
   3043 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3044 		return
   3045 	}
   3046 
   3047 	defer cleanupBucket(bucketName, c)
   3048 
   3049 	// Generate 33K of data.
   3050 	bufSize := dataFileMap["datafile-33-kB"]
   3051 	reader := getDataReader("datafile-33-kB")
   3052 	defer reader.Close()
   3053 
   3054 	// Save the data
   3055 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   3056 	args["objectName"] = objectName
   3057 
   3058 	buf, err := io.ReadAll(reader)
   3059 	if err != nil {
   3060 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   3061 		return
   3062 	}
   3063 
   3064 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   3065 	if err != nil {
   3066 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   3067 		return
   3068 	}
   3069 
   3070 	// Read the data back
   3071 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   3072 	if err != nil {
   3073 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   3074 		return
   3075 	}
   3076 
   3077 	st, err := r.Stat()
   3078 	if err != nil {
   3079 		logError(testName, function, args, startTime, "", "Stat failed", err)
   3080 		return
   3081 	}
   3082 
   3083 	if st.Size != int64(bufSize) {
   3084 		logError(testName, function, args, startTime, "", "Number of bytes read does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
   3085 		return
   3086 	}
   3087 
   3088 	pos, err := r.Seek(-100, 2)
   3089 	if err != nil {
   3090 		logError(testName, function, args, startTime, "", "Object Seek failed", err)
   3091 		return
   3092 	}
   3093 	if pos != st.Size-100 {
   3094 		logError(testName, function, args, startTime, "", "Incorrect position", err)
   3095 		return
   3096 	}
   3097 	buf2 := make([]byte, 100)
   3098 	m, err := readFull(r, buf2)
   3099 	if err != nil {
   3100 		logError(testName, function, args, startTime, "", "Error reading through readFull", err)
   3101 		return
   3102 	}
   3103 	if m != len(buf2) {
   3104 		logError(testName, function, args, startTime, "", "Number of bytes dont match, expected "+string(len(buf2))+" got "+string(m), err)
   3105 		return
   3106 	}
   3107 	hexBuf1 := fmt.Sprintf("%02x", buf[len(buf)-100:])
   3108 	hexBuf2 := fmt.Sprintf("%02x", buf2[:m])
   3109 	if hexBuf1 != hexBuf2 {
   3110 		logError(testName, function, args, startTime, "", "Values at same index dont match", err)
   3111 		return
   3112 	}
   3113 	pos, err = r.Seek(-100, 2)
   3114 	if err != nil {
   3115 		logError(testName, function, args, startTime, "", "Object Seek failed", err)
   3116 		return
   3117 	}
   3118 	if pos != st.Size-100 {
   3119 		logError(testName, function, args, startTime, "", "Incorrect position", err)
   3120 		return
   3121 	}
   3122 	if err = r.Close(); err != nil {
   3123 		logError(testName, function, args, startTime, "", "ObjectClose failed", err)
   3124 		return
   3125 	}
   3126 
   3127 	successLogger(testName, function, args, startTime).Info()
   3128 }
   3129 
   3130 // Test get object reader to not throw error on being closed twice.
   3131 func testGetObjectClosedTwice() {
   3132 	// initialize logging params
   3133 	startTime := time.Now()
   3134 	testName := getFuncName()
   3135 	function := "GetObject(bucketName, objectName)"
   3136 	args := map[string]interface{}{}
   3137 
   3138 	// Seed random based on current time.
   3139 	rand.Seed(time.Now().Unix())
   3140 
   3141 	// Instantiate new minio client object.
   3142 	c, err := minio.New(os.Getenv(serverEndpoint),
   3143 		&minio.Options{
   3144 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3145 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3146 		})
   3147 	if err != nil {
   3148 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3149 		return
   3150 	}
   3151 
   3152 	// Enable tracing, write to stderr.
   3153 	// c.TraceOn(os.Stderr)
   3154 
   3155 	// Set user agent.
   3156 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3157 
   3158 	// Generate a new random bucket name.
   3159 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3160 	args["bucketName"] = bucketName
   3161 
   3162 	// Make a new bucket.
   3163 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3164 	if err != nil {
   3165 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3166 		return
   3167 	}
   3168 
   3169 	defer cleanupBucket(bucketName, c)
   3170 
   3171 	// Generate 33K of data.
   3172 	bufSize := dataFileMap["datafile-33-kB"]
   3173 	reader := getDataReader("datafile-33-kB")
   3174 	defer reader.Close()
   3175 
   3176 	// Save the data
   3177 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   3178 	args["objectName"] = objectName
   3179 
   3180 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   3181 	if err != nil {
   3182 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   3183 		return
   3184 	}
   3185 
   3186 	// Read the data back
   3187 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   3188 	if err != nil {
   3189 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   3190 		return
   3191 	}
   3192 
   3193 	st, err := r.Stat()
   3194 	if err != nil {
   3195 		logError(testName, function, args, startTime, "", "Stat failed", err)
   3196 		return
   3197 	}
   3198 	if st.Size != int64(bufSize) {
   3199 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
   3200 		return
   3201 	}
   3202 	if err := crcMatchesName(r, "datafile-33-kB"); err != nil {
   3203 		logError(testName, function, args, startTime, "", "data CRC check failed", err)
   3204 		return
   3205 	}
   3206 	if err := r.Close(); err != nil {
   3207 		logError(testName, function, args, startTime, "", "Object Close failed", err)
   3208 		return
   3209 	}
   3210 	if err := r.Close(); err == nil {
   3211 		logError(testName, function, args, startTime, "", "Already closed object. No error returned", err)
   3212 		return
   3213 	}
   3214 
   3215 	successLogger(testName, function, args, startTime).Info()
   3216 }
   3217 
   3218 // Test RemoveObjects request where context cancels after timeout
   3219 func testRemoveObjectsContext() {
   3220 	// Initialize logging params.
   3221 	startTime := time.Now()
   3222 	testName := getFuncName()
   3223 	function := "RemoveObjects(ctx, bucketName, objectsCh)"
   3224 	args := map[string]interface{}{
   3225 		"bucketName": "",
   3226 	}
   3227 
   3228 	// Seed random based on current tie.
   3229 	rand.Seed(time.Now().Unix())
   3230 
   3231 	// Instantiate new minio client.
   3232 	c, err := minio.New(os.Getenv(serverEndpoint),
   3233 		&minio.Options{
   3234 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3235 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3236 		})
   3237 	if err != nil {
   3238 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3239 		return
   3240 	}
   3241 
   3242 	// Set user agent.
   3243 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3244 	// Enable tracing, write to stdout.
   3245 	// c.TraceOn(os.Stderr)
   3246 
   3247 	// Generate a new random bucket name.
   3248 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3249 	args["bucketName"] = bucketName
   3250 
   3251 	// Make a new bucket.
   3252 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3253 	if err != nil {
   3254 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3255 		return
   3256 	}
   3257 
   3258 	defer cleanupBucket(bucketName, c)
   3259 
   3260 	// Generate put data.
   3261 	r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
   3262 
   3263 	// Multi remove of 20 objects.
   3264 	nrObjects := 20
   3265 	objectsCh := make(chan minio.ObjectInfo)
   3266 	go func() {
   3267 		defer close(objectsCh)
   3268 		for i := 0; i < nrObjects; i++ {
   3269 			objectName := "sample" + strconv.Itoa(i) + ".txt"
   3270 			info, err := c.PutObject(context.Background(), bucketName, objectName, r, 8,
   3271 				minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3272 			if err != nil {
   3273 				logError(testName, function, args, startTime, "", "PutObject failed", err)
   3274 				continue
   3275 			}
   3276 			objectsCh <- minio.ObjectInfo{
   3277 				Key:       info.Key,
   3278 				VersionID: info.VersionID,
   3279 			}
   3280 		}
   3281 	}()
   3282 	// Set context to cancel in 1 nanosecond.
   3283 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   3284 	args["ctx"] = ctx
   3285 	defer cancel()
   3286 
   3287 	// Call RemoveObjects API with short timeout.
   3288 	errorCh := c.RemoveObjects(ctx, bucketName, objectsCh, minio.RemoveObjectsOptions{})
   3289 	// Check for error.
   3290 	select {
   3291 	case r := <-errorCh:
   3292 		if r.Err == nil {
   3293 			logError(testName, function, args, startTime, "", "RemoveObjects should fail on short timeout", err)
   3294 			return
   3295 		}
   3296 	}
   3297 	// Set context with longer timeout.
   3298 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
   3299 	args["ctx"] = ctx
   3300 	defer cancel()
   3301 	// Perform RemoveObjects with the longer timeout. Expect the removals to succeed.
   3302 	errorCh = c.RemoveObjects(ctx, bucketName, objectsCh, minio.RemoveObjectsOptions{})
   3303 	select {
   3304 	case r, more := <-errorCh:
   3305 		if more || r.Err != nil {
   3306 			logError(testName, function, args, startTime, "", "Unexpected error", r.Err)
   3307 			return
   3308 		}
   3309 	}
   3310 
   3311 	successLogger(testName, function, args, startTime).Info()
   3312 }
   3313 
   3314 // Test removing multiple objects with Remove API
   3315 func testRemoveMultipleObjects() {
   3316 	// initialize logging params
   3317 	startTime := time.Now()
   3318 	testName := getFuncName()
   3319 	function := "RemoveObjects(bucketName, objectsCh)"
   3320 	args := map[string]interface{}{
   3321 		"bucketName": "",
   3322 	}
   3323 
   3324 	// Seed random based on current time.
   3325 	rand.Seed(time.Now().Unix())
   3326 
   3327 	// Instantiate new minio client object.
   3328 	c, err := minio.New(os.Getenv(serverEndpoint),
   3329 		&minio.Options{
   3330 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3331 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3332 		})
   3333 	if err != nil {
   3334 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3335 		return
   3336 	}
   3337 
   3338 	// Set user agent.
   3339 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3340 
   3341 	// Enable tracing, write to stdout.
   3342 	// c.TraceOn(os.Stderr)
   3343 
   3344 	// Generate a new random bucket name.
   3345 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3346 	args["bucketName"] = bucketName
   3347 
   3348 	// Make a new bucket.
   3349 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3350 	if err != nil {
   3351 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3352 		return
   3353 	}
   3354 
   3355 	defer cleanupBucket(bucketName, c)
   3356 
   3357 	r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
   3358 
   3359 	// Multi remove of 1100 objects
   3360 	nrObjects := 200
   3361 
   3362 	objectsCh := make(chan minio.ObjectInfo)
   3363 
   3364 	go func() {
   3365 		defer close(objectsCh)
   3366 		// Upload objects and send them to objectsCh
   3367 		for i := 0; i < nrObjects; i++ {
   3368 			objectName := "sample" + strconv.Itoa(i) + ".txt"
   3369 			info, err := c.PutObject(context.Background(), bucketName, objectName, r, 8,
   3370 				minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3371 			if err != nil {
   3372 				logError(testName, function, args, startTime, "", "PutObject failed", err)
   3373 				continue
   3374 			}
   3375 			objectsCh <- minio.ObjectInfo{
   3376 				Key:       info.Key,
   3377 				VersionID: info.VersionID,
   3378 			}
   3379 		}
   3380 	}()
   3381 
   3382 	// Call RemoveObjects API
   3383 	errorCh := c.RemoveObjects(context.Background(), bucketName, objectsCh, minio.RemoveObjectsOptions{})
   3384 
   3385 	// Check if errorCh doesn't receive any error
   3386 	select {
   3387 	case r, more := <-errorCh:
   3388 		if more {
   3389 			logError(testName, function, args, startTime, "", "Unexpected error", r.Err)
   3390 			return
   3391 		}
   3392 	}
   3393 
   3394 	successLogger(testName, function, args, startTime).Info()
   3395 }
   3396 
   3397 // Test removing multiple objects and check for results
   3398 func testRemoveMultipleObjectsWithResult() {
   3399 	// initialize logging params
   3400 	startTime := time.Now()
   3401 	testName := getFuncName()
   3402 	function := "RemoveObjects(bucketName, objectsCh)"
   3403 	args := map[string]interface{}{
   3404 		"bucketName": "",
   3405 	}
   3406 
   3407 	// Seed random based on current time.
   3408 	rand.Seed(time.Now().Unix())
   3409 
   3410 	// Instantiate new minio client object.
   3411 	c, err := minio.New(os.Getenv(serverEndpoint),
   3412 		&minio.Options{
   3413 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3414 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3415 		})
   3416 	if err != nil {
   3417 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3418 		return
   3419 	}
   3420 
   3421 	// Set user agent.
   3422 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3423 
   3424 	// Enable tracing, write to stdout.
   3425 	// c.TraceOn(os.Stderr)
   3426 
   3427 	// Generate a new random bucket name.
   3428 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3429 	args["bucketName"] = bucketName
   3430 
   3431 	// Make a new bucket.
   3432 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
   3433 	if err != nil {
   3434 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3435 		return
   3436 	}
   3437 
   3438 	defer cleanupVersionedBucket(bucketName, c)
   3439 
   3440 	r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
   3441 
   3442 	nrObjects := 10
   3443 	nrLockedObjects := 5
   3444 
   3445 	objectsCh := make(chan minio.ObjectInfo)
   3446 
   3447 	go func() {
   3448 		defer close(objectsCh)
   3449 		// Upload objects and send them to objectsCh
   3450 		for i := 0; i < nrObjects; i++ {
   3451 			objectName := "sample" + strconv.Itoa(i) + ".txt"
   3452 			info, err := c.PutObject(context.Background(), bucketName, objectName, r, 8,
   3453 				minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3454 			if err != nil {
   3455 				logError(testName, function, args, startTime, "", "PutObject failed", err)
   3456 				return
   3457 			}
   3458 			if i < nrLockedObjects {
   3459 				// t := time.Date(2130, time.April, 25, 14, 0, 0, 0, time.UTC)
   3460 				t := time.Now().Add(5 * time.Minute)
   3461 				m := minio.RetentionMode(minio.Governance)
   3462 				opts := minio.PutObjectRetentionOptions{
   3463 					GovernanceBypass: false,
   3464 					RetainUntilDate:  &t,
   3465 					Mode:             &m,
   3466 					VersionID:        info.VersionID,
   3467 				}
   3468 				err = c.PutObjectRetention(context.Background(), bucketName, objectName, opts)
   3469 				if err != nil {
   3470 					logError(testName, function, args, startTime, "", "Error setting retention", err)
   3471 					return
   3472 				}
   3473 			}
   3474 
   3475 			objectsCh <- minio.ObjectInfo{
   3476 				Key:       info.Key,
   3477 				VersionID: info.VersionID,
   3478 			}
   3479 		}
   3480 	}()
   3481 
   3482 	// Call RemoveObjects API
   3483 	resultCh := c.RemoveObjectsWithResult(context.Background(), bucketName, objectsCh, minio.RemoveObjectsOptions{})
   3484 
   3485 	var foundNil, foundErr int
   3486 
   3487 	for {
   3488 		// Check if errorCh doesn't receive any error
   3489 		select {
   3490 		case deleteRes, ok := <-resultCh:
   3491 			if !ok {
   3492 				goto out
   3493 			}
   3494 			if deleteRes.ObjectName == "" {
   3495 				logError(testName, function, args, startTime, "", "Unexpected object name", nil)
   3496 				return
   3497 			}
   3498 			if deleteRes.ObjectVersionID == "" {
   3499 				logError(testName, function, args, startTime, "", "Unexpected object version ID", nil)
   3500 				return
   3501 			}
   3502 
   3503 			if deleteRes.Err == nil {
   3504 				foundNil++
   3505 			} else {
   3506 				foundErr++
   3507 			}
   3508 		}
   3509 	}
   3510 out:
   3511 	if foundNil+foundErr != nrObjects {
   3512 		logError(testName, function, args, startTime, "", "Unexpected number of results", nil)
   3513 		return
   3514 	}
   3515 
   3516 	if foundNil != nrObjects-nrLockedObjects {
   3517 		logError(testName, function, args, startTime, "", "Unexpected number of nil errors", nil)
   3518 		return
   3519 	}
   3520 
   3521 	if foundErr != nrLockedObjects {
   3522 		logError(testName, function, args, startTime, "", "Unexpected number of errors", nil)
   3523 		return
   3524 	}
   3525 
   3526 	successLogger(testName, function, args, startTime).Info()
   3527 }
   3528 
   3529 // Tests FPutObject of a big file to trigger multipart
   3530 func testFPutObjectMultipart() {
   3531 	// initialize logging params
   3532 	startTime := time.Now()
   3533 	testName := getFuncName()
   3534 	function := "FPutObject(bucketName, objectName, fileName, opts)"
   3535 	args := map[string]interface{}{
   3536 		"bucketName": "",
   3537 		"objectName": "",
   3538 		"fileName":   "",
   3539 		"opts":       "",
   3540 	}
   3541 
   3542 	// Seed random based on current time.
   3543 	rand.Seed(time.Now().Unix())
   3544 
   3545 	// Instantiate new minio client object.
   3546 	c, err := minio.New(os.Getenv(serverEndpoint),
   3547 		&minio.Options{
   3548 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3549 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3550 		})
   3551 	if err != nil {
   3552 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3553 		return
   3554 	}
   3555 
   3556 	// Enable tracing, write to stderr.
   3557 	// c.TraceOn(os.Stderr)
   3558 
   3559 	// Set user agent.
   3560 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3561 
   3562 	// Generate a new random bucket name.
   3563 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3564 	args["bucketName"] = bucketName
   3565 
   3566 	// Make a new bucket.
   3567 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3568 	if err != nil {
   3569 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3570 		return
   3571 	}
   3572 
   3573 	defer cleanupBucket(bucketName, c)
   3574 
   3575 	// Upload 4 parts to utilize all 3 'workers' in multipart and still have a part to upload.
   3576 	fileName := getMintDataDirFilePath("datafile-129-MB")
   3577 	if fileName == "" {
   3578 		// Make a temp file with minPartSize bytes of data.
   3579 		file, err := os.CreateTemp(os.TempDir(), "FPutObjectTest")
   3580 		if err != nil {
   3581 			logError(testName, function, args, startTime, "", "TempFile creation failed", err)
   3582 			return
   3583 		}
   3584 		// Upload 2 parts to utilize all 3 'workers' in multipart and still have a part to upload.
   3585 		if _, err = io.Copy(file, getDataReader("datafile-129-MB")); err != nil {
   3586 			logError(testName, function, args, startTime, "", "Copy failed", err)
   3587 			return
   3588 		}
   3589 		if err = file.Close(); err != nil {
   3590 			logError(testName, function, args, startTime, "", "File Close failed", err)
   3591 			return
   3592 		}
   3593 		fileName = file.Name()
   3594 		args["fileName"] = fileName
   3595 	}
   3596 	totalSize := dataFileMap["datafile-129-MB"]
   3597 	// Set base object name
   3598 	objectName := bucketName + "FPutObject" + "-standard"
   3599 	args["objectName"] = objectName
   3600 
   3601 	objectContentType := "testapplication/octet-stream"
   3602 	args["objectContentType"] = objectContentType
   3603 
   3604 	// Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
   3605 	_, err = c.FPutObject(context.Background(), bucketName, objectName, fileName, minio.PutObjectOptions{ContentType: objectContentType})
   3606 	if err != nil {
   3607 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   3608 		return
   3609 	}
   3610 
   3611 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   3612 	if err != nil {
   3613 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   3614 		return
   3615 	}
   3616 	objInfo, err := r.Stat()
   3617 	if err != nil {
   3618 		logError(testName, function, args, startTime, "", "Unexpected error", err)
   3619 		return
   3620 	}
   3621 	if objInfo.Size != int64(totalSize) {
   3622 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(totalSize))+" got "+string(objInfo.Size), err)
   3623 		return
   3624 	}
   3625 	if objInfo.ContentType != objectContentType && objInfo.ContentType != "application/octet-stream" {
   3626 		logError(testName, function, args, startTime, "", "ContentType doesn't match", err)
   3627 		return
   3628 	}
   3629 
   3630 	successLogger(testName, function, args, startTime).Info()
   3631 }
   3632 
   3633 // Tests FPutObject with null contentType (default = application/octet-stream)
   3634 func testFPutObject() {
   3635 	// initialize logging params
   3636 	startTime := time.Now()
   3637 	testName := getFuncName()
   3638 	function := "FPutObject(bucketName, objectName, fileName, opts)"
   3639 
   3640 	args := map[string]interface{}{
   3641 		"bucketName": "",
   3642 		"objectName": "",
   3643 		"fileName":   "",
   3644 		"opts":       "",
   3645 	}
   3646 
   3647 	// Seed random based on current time.
   3648 	rand.Seed(time.Now().Unix())
   3649 
   3650 	// Instantiate new minio client object.
   3651 	c, err := minio.New(os.Getenv(serverEndpoint),
   3652 		&minio.Options{
   3653 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3654 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3655 		})
   3656 	if err != nil {
   3657 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3658 		return
   3659 	}
   3660 
   3661 	// Enable tracing, write to stderr.
   3662 	// c.TraceOn(os.Stderr)
   3663 
   3664 	// Set user agent.
   3665 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3666 
   3667 	// Generate a new random bucket name.
   3668 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3669 	location := "us-east-1"
   3670 
   3671 	// Make a new bucket.
   3672 	args["bucketName"] = bucketName
   3673 	args["location"] = location
   3674 	function = "MakeBucket(bucketName, location)"
   3675 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: location})
   3676 	if err != nil {
   3677 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3678 		return
   3679 	}
   3680 
   3681 	defer cleanupBucket(bucketName, c)
   3682 
   3683 	// Upload 3 parts worth of data to use all 3 of multiparts 'workers' and have an extra part.
   3684 	// Use different data in part for multipart tests to check parts are uploaded in correct order.
   3685 	fName := getMintDataDirFilePath("datafile-129-MB")
   3686 	if fName == "" {
   3687 		// Make a temp file with minPartSize bytes of data.
   3688 		file, err := os.CreateTemp(os.TempDir(), "FPutObjectTest")
   3689 		if err != nil {
   3690 			logError(testName, function, args, startTime, "", "TempFile creation failed", err)
   3691 			return
   3692 		}
   3693 
   3694 		// Upload 3 parts to utilize all 3 'workers' in multipart and still have a part to upload.
   3695 		if _, err = io.Copy(file, getDataReader("datafile-129-MB")); err != nil {
   3696 			logError(testName, function, args, startTime, "", "File copy failed", err)
   3697 			return
   3698 		}
   3699 		// Close the file pro-actively for windows.
   3700 		if err = file.Close(); err != nil {
   3701 			logError(testName, function, args, startTime, "", "File close failed", err)
   3702 			return
   3703 		}
   3704 		defer os.Remove(file.Name())
   3705 		fName = file.Name()
   3706 	}
   3707 
   3708 	// Set base object name
   3709 	function = "FPutObject(bucketName, objectName, fileName, opts)"
   3710 	objectName := bucketName + "FPutObject"
   3711 	args["objectName"] = objectName + "-standard"
   3712 	args["fileName"] = fName
   3713 	args["opts"] = minio.PutObjectOptions{ContentType: "application/octet-stream"}
   3714 
   3715 	// Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
   3716 	ui, err := c.FPutObject(context.Background(), bucketName, objectName+"-standard", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3717 	if err != nil {
   3718 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   3719 		return
   3720 	}
   3721 
   3722 	if ui.Size != int64(dataFileMap["datafile-129-MB"]) {
   3723 		logError(testName, function, args, startTime, "", "FPutObject returned an unexpected upload size", err)
   3724 		return
   3725 	}
   3726 
   3727 	// Perform FPutObject with no contentType provided (Expecting application/octet-stream)
   3728 	args["objectName"] = objectName + "-Octet"
   3729 	_, err = c.FPutObject(context.Background(), bucketName, objectName+"-Octet", fName, minio.PutObjectOptions{})
   3730 	if err != nil {
   3731 		logError(testName, function, args, startTime, "", "File close failed", err)
   3732 		return
   3733 	}
   3734 
   3735 	srcFile, err := os.Open(fName)
   3736 	if err != nil {
   3737 		logError(testName, function, args, startTime, "", "File open failed", err)
   3738 		return
   3739 	}
   3740 	defer srcFile.Close()
   3741 	// Add extension to temp file name
   3742 	tmpFile, err := os.Create(fName + ".gtar")
   3743 	if err != nil {
   3744 		logError(testName, function, args, startTime, "", "File create failed", err)
   3745 		return
   3746 	}
   3747 	_, err = io.Copy(tmpFile, srcFile)
   3748 	if err != nil {
   3749 		logError(testName, function, args, startTime, "", "File copy failed", err)
   3750 		return
   3751 	}
   3752 	tmpFile.Close()
   3753 
   3754 	// Perform FPutObject with no contentType provided (Expecting application/x-gtar)
   3755 	args["objectName"] = objectName + "-GTar"
   3756 	args["opts"] = minio.PutObjectOptions{}
   3757 	_, err = c.FPutObject(context.Background(), bucketName, objectName+"-GTar", fName+".gtar", minio.PutObjectOptions{})
   3758 	if err != nil {
   3759 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   3760 		return
   3761 	}
   3762 
   3763 	// Check headers
   3764 	function = "StatObject(bucketName, objectName, opts)"
   3765 	args["objectName"] = objectName + "-standard"
   3766 	rStandard, err := c.StatObject(context.Background(), bucketName, objectName+"-standard", minio.StatObjectOptions{})
   3767 	if err != nil {
   3768 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   3769 		return
   3770 	}
   3771 	if rStandard.ContentType != "application/octet-stream" {
   3772 		logError(testName, function, args, startTime, "", "ContentType does not match, expected application/octet-stream, got "+rStandard.ContentType, err)
   3773 		return
   3774 	}
   3775 
   3776 	function = "StatObject(bucketName, objectName, opts)"
   3777 	args["objectName"] = objectName + "-Octet"
   3778 	rOctet, err := c.StatObject(context.Background(), bucketName, objectName+"-Octet", minio.StatObjectOptions{})
   3779 	if err != nil {
   3780 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   3781 		return
   3782 	}
   3783 	if rOctet.ContentType != "application/octet-stream" {
   3784 		logError(testName, function, args, startTime, "", "ContentType does not match, expected application/octet-stream, got "+rOctet.ContentType, err)
   3785 		return
   3786 	}
   3787 
   3788 	function = "StatObject(bucketName, objectName, opts)"
   3789 	args["objectName"] = objectName + "-GTar"
   3790 	rGTar, err := c.StatObject(context.Background(), bucketName, objectName+"-GTar", minio.StatObjectOptions{})
   3791 	if err != nil {
   3792 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   3793 		return
   3794 	}
   3795 	if rGTar.ContentType != "application/x-gtar" && rGTar.ContentType != "application/octet-stream" && rGTar.ContentType != "application/x-tar" {
   3796 		logError(testName, function, args, startTime, "", "ContentType does not match, expected application/x-tar or application/octet-stream, got "+rGTar.ContentType, err)
   3797 		return
   3798 	}
   3799 
   3800 	os.Remove(fName + ".gtar")
   3801 	successLogger(testName, function, args, startTime).Info()
   3802 }
   3803 
   3804 // Tests FPutObject request when context cancels after timeout
   3805 func testFPutObjectContext() {
   3806 	// initialize logging params
   3807 	startTime := time.Now()
   3808 	testName := getFuncName()
   3809 	function := "FPutObject(bucketName, objectName, fileName, opts)"
   3810 	args := map[string]interface{}{
   3811 		"bucketName": "",
   3812 		"objectName": "",
   3813 		"fileName":   "",
   3814 		"opts":       "",
   3815 	}
   3816 	// Seed random based on current time.
   3817 	rand.Seed(time.Now().Unix())
   3818 
   3819 	// Instantiate new minio client object.
   3820 	c, err := minio.New(os.Getenv(serverEndpoint),
   3821 		&minio.Options{
   3822 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3823 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3824 		})
   3825 	if err != nil {
   3826 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3827 		return
   3828 	}
   3829 
   3830 	// Enable tracing, write to stderr.
   3831 	// c.TraceOn(os.Stderr)
   3832 
   3833 	// Set user agent.
   3834 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3835 
   3836 	// Generate a new random bucket name.
   3837 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3838 	args["bucketName"] = bucketName
   3839 
   3840 	// Make a new bucket.
   3841 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3842 	if err != nil {
   3843 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3844 		return
   3845 	}
   3846 
   3847 	defer cleanupBucket(bucketName, c)
   3848 
   3849 	// Upload 1 parts worth of data to use multipart upload.
   3850 	// Use different data in part for multipart tests to check parts are uploaded in correct order.
   3851 	fName := getMintDataDirFilePath("datafile-1-MB")
   3852 	if fName == "" {
   3853 		// Make a temp file with 1 MiB bytes of data.
   3854 		file, err := os.CreateTemp(os.TempDir(), "FPutObjectContextTest")
   3855 		if err != nil {
   3856 			logError(testName, function, args, startTime, "", "TempFile creation failed", err)
   3857 			return
   3858 		}
   3859 
   3860 		// Upload 1 parts to trigger multipart upload
   3861 		if _, err = io.Copy(file, getDataReader("datafile-1-MB")); err != nil {
   3862 			logError(testName, function, args, startTime, "", "File copy failed", err)
   3863 			return
   3864 		}
   3865 		// Close the file pro-actively for windows.
   3866 		if err = file.Close(); err != nil {
   3867 			logError(testName, function, args, startTime, "", "File close failed", err)
   3868 			return
   3869 		}
   3870 		defer os.Remove(file.Name())
   3871 		fName = file.Name()
   3872 	}
   3873 
   3874 	// Set base object name
   3875 	objectName := bucketName + "FPutObjectContext"
   3876 	args["objectName"] = objectName
   3877 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   3878 	args["ctx"] = ctx
   3879 	defer cancel()
   3880 
   3881 	// Perform FPutObject with contentType provided (Expecting application/octet-stream)
   3882 	_, err = c.FPutObject(ctx, bucketName, objectName+"-Shorttimeout", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3883 	if err == nil {
   3884 		logError(testName, function, args, startTime, "", "FPutObject should fail on short timeout", err)
   3885 		return
   3886 	}
   3887 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
   3888 	defer cancel()
   3889 	// Perform FPutObject with a long timeout. Expect the put object to succeed
   3890 	_, err = c.FPutObject(ctx, bucketName, objectName+"-Longtimeout", fName, minio.PutObjectOptions{})
   3891 	if err != nil {
   3892 		logError(testName, function, args, startTime, "", "FPutObject shouldn't fail on long timeout", err)
   3893 		return
   3894 	}
   3895 
   3896 	_, err = c.StatObject(context.Background(), bucketName, objectName+"-Longtimeout", minio.StatObjectOptions{})
   3897 	if err != nil {
   3898 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   3899 		return
   3900 	}
   3901 
   3902 	successLogger(testName, function, args, startTime).Info()
   3903 }
   3904 
   3905 // Tests FPutObject request when context cancels after timeout
   3906 func testFPutObjectContextV2() {
   3907 	// initialize logging params
   3908 	startTime := time.Now()
   3909 	testName := getFuncName()
   3910 	function := "FPutObjectContext(ctx, bucketName, objectName, fileName, opts)"
   3911 	args := map[string]interface{}{
   3912 		"bucketName": "",
   3913 		"objectName": "",
   3914 		"opts":       "minio.PutObjectOptions{ContentType:objectContentType}",
   3915 	}
   3916 	// Seed random based on current time.
   3917 	rand.Seed(time.Now().Unix())
   3918 
   3919 	// Instantiate new minio client object.
   3920 	c, err := minio.New(os.Getenv(serverEndpoint),
   3921 		&minio.Options{
   3922 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   3923 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   3924 		})
   3925 	if err != nil {
   3926 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   3927 		return
   3928 	}
   3929 
   3930 	// Enable tracing, write to stderr.
   3931 	// c.TraceOn(os.Stderr)
   3932 
   3933 	// Set user agent.
   3934 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   3935 
   3936 	// Generate a new random bucket name.
   3937 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   3938 	args["bucketName"] = bucketName
   3939 
   3940 	// Make a new bucket.
   3941 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   3942 	if err != nil {
   3943 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   3944 		return
   3945 	}
   3946 
   3947 	defer cleanupBucket(bucketName, c)
   3948 
   3949 	// Upload 1 parts worth of data to use multipart upload.
   3950 	// Use different data in part for multipart tests to check parts are uploaded in correct order.
   3951 	fName := getMintDataDirFilePath("datafile-1-MB")
   3952 	if fName == "" {
   3953 		// Make a temp file with 1 MiB bytes of data.
   3954 		file, err := os.CreateTemp(os.TempDir(), "FPutObjectContextTest")
   3955 		if err != nil {
   3956 			logError(testName, function, args, startTime, "", "Temp file creation failed", err)
   3957 			return
   3958 		}
   3959 
   3960 		// Upload 1 parts to trigger multipart upload
   3961 		if _, err = io.Copy(file, getDataReader("datafile-1-MB")); err != nil {
   3962 			logError(testName, function, args, startTime, "", "File copy failed", err)
   3963 			return
   3964 		}
   3965 
   3966 		// Close the file pro-actively for windows.
   3967 		if err = file.Close(); err != nil {
   3968 			logError(testName, function, args, startTime, "", "File close failed", err)
   3969 			return
   3970 		}
   3971 		defer os.Remove(file.Name())
   3972 		fName = file.Name()
   3973 	}
   3974 
   3975 	// Set base object name
   3976 	objectName := bucketName + "FPutObjectContext"
   3977 	args["objectName"] = objectName
   3978 
   3979 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   3980 	args["ctx"] = ctx
   3981 	defer cancel()
   3982 
   3983 	// Perform FPutObject with contentType provided (Expecting application/octet-stream)
   3984 	_, err = c.FPutObject(ctx, bucketName, objectName+"-Shorttimeout", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
   3985 	if err == nil {
   3986 		logError(testName, function, args, startTime, "", "FPutObject should fail on short timeout", err)
   3987 		return
   3988 	}
   3989 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
   3990 	defer cancel()
   3991 	// Perform FPutObject with a long timeout. Expect the put object to succeed
   3992 	_, err = c.FPutObject(ctx, bucketName, objectName+"-Longtimeout", fName, minio.PutObjectOptions{})
   3993 	if err != nil {
   3994 		logError(testName, function, args, startTime, "", "FPutObject shouldn't fail on longer timeout", err)
   3995 		return
   3996 	}
   3997 
   3998 	_, err = c.StatObject(context.Background(), bucketName, objectName+"-Longtimeout", minio.StatObjectOptions{})
   3999 	if err != nil {
   4000 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   4001 		return
   4002 	}
   4003 
   4004 	successLogger(testName, function, args, startTime).Info()
   4005 }
   4006 
   4007 // Test validates putObject with context to see if request cancellation is honored.
   4008 func testPutObjectContext() {
   4009 	// initialize logging params
   4010 	startTime := time.Now()
   4011 	testName := getFuncName()
   4012 	function := "PutObject(ctx, bucketName, objectName, fileName, opts)"
   4013 	args := map[string]interface{}{
   4014 		"ctx":        "",
   4015 		"bucketName": "",
   4016 		"objectName": "",
   4017 		"opts":       "",
   4018 	}
   4019 
   4020 	// Instantiate new minio client object.
   4021 	c, err := minio.New(os.Getenv(serverEndpoint),
   4022 		&minio.Options{
   4023 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4024 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4025 		})
   4026 	if err != nil {
   4027 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4028 		return
   4029 	}
   4030 
   4031 	// Enable tracing, write to stderr.
   4032 	// c.TraceOn(os.Stderr)
   4033 
   4034 	// Set user agent.
   4035 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4036 
   4037 	// Make a new bucket.
   4038 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4039 	args["bucketName"] = bucketName
   4040 
   4041 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4042 	if err != nil {
   4043 		logError(testName, function, args, startTime, "", "MakeBucket call failed", err)
   4044 		return
   4045 	}
   4046 
   4047 	defer cleanupBucket(bucketName, c)
   4048 
   4049 	bufSize := dataFileMap["datafile-33-kB"]
   4050 	reader := getDataReader("datafile-33-kB")
   4051 	defer reader.Close()
   4052 	objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
   4053 	args["objectName"] = objectName
   4054 
   4055 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   4056 	cancel()
   4057 	args["ctx"] = ctx
   4058 	args["opts"] = minio.PutObjectOptions{ContentType: "binary/octet-stream"}
   4059 
   4060 	_, err = c.PutObject(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4061 	if err == nil {
   4062 		logError(testName, function, args, startTime, "", "PutObject should fail on short timeout", err)
   4063 		return
   4064 	}
   4065 
   4066 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
   4067 	args["ctx"] = ctx
   4068 
   4069 	defer cancel()
   4070 	reader = getDataReader("datafile-33-kB")
   4071 	defer reader.Close()
   4072 	_, err = c.PutObject(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4073 	if err != nil {
   4074 		logError(testName, function, args, startTime, "", "PutObject with long timeout failed", err)
   4075 		return
   4076 	}
   4077 
   4078 	successLogger(testName, function, args, startTime).Info()
   4079 }
   4080 
   4081 // Tests get object with s3zip extensions.
   4082 func testGetObjectS3Zip() {
   4083 	// initialize logging params
   4084 	startTime := time.Now()
   4085 	testName := getFuncName()
   4086 	function := "GetObject(bucketName, objectName)"
   4087 	args := map[string]interface{}{"x-minio-extract": true}
   4088 
   4089 	// Seed random based on current time.
   4090 	rand.Seed(time.Now().Unix())
   4091 
   4092 	// Instantiate new minio client object.
   4093 	c, err := minio.New(os.Getenv(serverEndpoint),
   4094 		&minio.Options{
   4095 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4096 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4097 		})
   4098 	if err != nil {
   4099 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4100 		return
   4101 	}
   4102 
   4103 	// Enable tracing, write to stderr.
   4104 	// c.TraceOn(os.Stderr)
   4105 
   4106 	// Set user agent.
   4107 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4108 
   4109 	// Generate a new random bucket name.
   4110 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4111 	args["bucketName"] = bucketName
   4112 
   4113 	// Make a new bucket.
   4114 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4115 	if err != nil {
   4116 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4117 		return
   4118 	}
   4119 
   4120 	defer func() {
   4121 		// Delete all objects and buckets
   4122 		if err = cleanupBucket(bucketName, c); err != nil {
   4123 			logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   4124 			return
   4125 		}
   4126 	}()
   4127 
   4128 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "") + ".zip"
   4129 	args["objectName"] = objectName
   4130 
   4131 	var zipFile bytes.Buffer
   4132 	zw := zip.NewWriter(&zipFile)
   4133 	rng := rand.New(rand.NewSource(0xc0cac01a))
   4134 	const nFiles = 500
   4135 	for i := 0; i <= nFiles; i++ {
   4136 		if i == nFiles {
   4137 			// Make one large, compressible file.
   4138 			i = 1000000
   4139 		}
   4140 		b := make([]byte, i)
   4141 		if i < nFiles {
   4142 			rng.Read(b)
   4143 		}
   4144 		wc, err := zw.Create(fmt.Sprintf("test/small/file-%d.bin", i))
   4145 		if err != nil {
   4146 			logError(testName, function, args, startTime, "", "zw.Create failed", err)
   4147 			return
   4148 		}
   4149 		wc.Write(b)
   4150 	}
   4151 	err = zw.Close()
   4152 	if err != nil {
   4153 		logError(testName, function, args, startTime, "", "zw.Close failed", err)
   4154 		return
   4155 	}
   4156 	buf := zipFile.Bytes()
   4157 
   4158 	// Save the data
   4159 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4160 	if err != nil {
   4161 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4162 		return
   4163 	}
   4164 
   4165 	// Read the data back
   4166 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   4167 	if err != nil {
   4168 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   4169 		return
   4170 	}
   4171 
   4172 	st, err := r.Stat()
   4173 	if err != nil {
   4174 		logError(testName, function, args, startTime, "", "Stat object failed", err)
   4175 		return
   4176 	}
   4177 
   4178 	if st.Size != int64(len(buf)) {
   4179 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(len(buf))+", got "+string(st.Size), err)
   4180 		return
   4181 	}
   4182 	r.Close()
   4183 
   4184 	zr, err := zip.NewReader(bytes.NewReader(buf), int64(len(buf)))
   4185 	if err != nil {
   4186 		logError(testName, function, args, startTime, "", "zip.NewReader failed", err)
   4187 		return
   4188 	}
   4189 	lOpts := minio.ListObjectsOptions{}
   4190 	lOpts.Set("x-minio-extract", "true")
   4191 	lOpts.Prefix = objectName + "/"
   4192 	lOpts.Recursive = true
   4193 	list := c.ListObjects(context.Background(), bucketName, lOpts)
   4194 	listed := map[string]minio.ObjectInfo{}
   4195 	for item := range list {
   4196 		if item.Err != nil {
   4197 			break
   4198 		}
   4199 		listed[item.Key] = item
   4200 	}
   4201 	if len(listed) == 0 {
   4202 		// Assume we are running against non-minio.
   4203 		args["SKIPPED"] = true
   4204 		ignoredLog(testName, function, args, startTime, "s3zip does not appear to be present").Info()
   4205 		return
   4206 	}
   4207 
   4208 	for _, file := range zr.File {
   4209 		if file.FileInfo().IsDir() {
   4210 			continue
   4211 		}
   4212 		args["zipfile"] = file.Name
   4213 		zfr, err := file.Open()
   4214 		if err != nil {
   4215 			logError(testName, function, args, startTime, "", "file.Open failed", err)
   4216 			return
   4217 		}
   4218 		want, err := io.ReadAll(zfr)
   4219 		if err != nil {
   4220 			logError(testName, function, args, startTime, "", "fzip file read failed", err)
   4221 			return
   4222 		}
   4223 
   4224 		opts := minio.GetObjectOptions{}
   4225 		opts.Set("x-minio-extract", "true")
   4226 		key := path.Join(objectName, file.Name)
   4227 		r, err = c.GetObject(context.Background(), bucketName, key, opts)
   4228 		if err != nil {
   4229 			terr := minio.ToErrorResponse(err)
   4230 			if terr.StatusCode != http.StatusNotFound {
   4231 				logError(testName, function, args, startTime, "", "GetObject failed", err)
   4232 			}
   4233 			return
   4234 		}
   4235 		got, err := io.ReadAll(r)
   4236 		if err != nil {
   4237 			logError(testName, function, args, startTime, "", "ReadAll failed", err)
   4238 			return
   4239 		}
   4240 		r.Close()
   4241 		if !bytes.Equal(want, got) {
   4242 			logError(testName, function, args, startTime, "", "Content mismatch", err)
   4243 			return
   4244 		}
   4245 		oi, ok := listed[key]
   4246 		if !ok {
   4247 			logError(testName, function, args, startTime, "", "Object Missing", fmt.Errorf("%s not present in listing", key))
   4248 			return
   4249 		}
   4250 		if int(oi.Size) != len(got) {
   4251 			logError(testName, function, args, startTime, "", "Object Size Incorrect", fmt.Errorf("listing %d, read %d", oi.Size, len(got)))
   4252 			return
   4253 		}
   4254 		delete(listed, key)
   4255 	}
   4256 	delete(args, "zipfile")
   4257 	if len(listed) > 0 {
   4258 		logError(testName, function, args, startTime, "", "Extra listed objects", fmt.Errorf("left over: %v", listed))
   4259 		return
   4260 	}
   4261 	successLogger(testName, function, args, startTime).Info()
   4262 }
   4263 
   4264 // Tests get object ReaderSeeker interface methods.
   4265 func testGetObjectReadSeekFunctional() {
   4266 	// initialize logging params
   4267 	startTime := time.Now()
   4268 	testName := getFuncName()
   4269 	function := "GetObject(bucketName, objectName)"
   4270 	args := map[string]interface{}{}
   4271 
   4272 	// Seed random based on current time.
   4273 	rand.Seed(time.Now().Unix())
   4274 
   4275 	// Instantiate new minio client object.
   4276 	c, err := minio.New(os.Getenv(serverEndpoint),
   4277 		&minio.Options{
   4278 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4279 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4280 		})
   4281 	if err != nil {
   4282 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4283 		return
   4284 	}
   4285 
   4286 	// Enable tracing, write to stderr.
   4287 	// c.TraceOn(os.Stderr)
   4288 
   4289 	// Set user agent.
   4290 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4291 
   4292 	// Generate a new random bucket name.
   4293 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4294 	args["bucketName"] = bucketName
   4295 
   4296 	// Make a new bucket.
   4297 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4298 	if err != nil {
   4299 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4300 		return
   4301 	}
   4302 
   4303 	defer func() {
   4304 		// Delete all objects and buckets
   4305 		if err = cleanupBucket(bucketName, c); err != nil {
   4306 			logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   4307 			return
   4308 		}
   4309 	}()
   4310 
   4311 	// Generate 33K of data.
   4312 	bufSize := dataFileMap["datafile-33-kB"]
   4313 	reader := getDataReader("datafile-33-kB")
   4314 	defer reader.Close()
   4315 
   4316 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4317 	args["objectName"] = objectName
   4318 
   4319 	buf, err := io.ReadAll(reader)
   4320 	if err != nil {
   4321 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   4322 		return
   4323 	}
   4324 
   4325 	// Save the data
   4326 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4327 	if err != nil {
   4328 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4329 		return
   4330 	}
   4331 
   4332 	// Read the data back
   4333 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   4334 	if err != nil {
   4335 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   4336 		return
   4337 	}
   4338 
   4339 	st, err := r.Stat()
   4340 	if err != nil {
   4341 		logError(testName, function, args, startTime, "", "Stat object failed", err)
   4342 		return
   4343 	}
   4344 
   4345 	if st.Size != int64(bufSize) {
   4346 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   4347 		return
   4348 	}
   4349 
   4350 	// This following function helps us to compare data from the reader after seek
   4351 	// with the data from the original buffer
   4352 	cmpData := func(r io.Reader, start, end int) {
   4353 		if end-start == 0 {
   4354 			return
   4355 		}
   4356 		buffer := bytes.NewBuffer([]byte{})
   4357 		if _, err := io.CopyN(buffer, r, int64(bufSize)); err != nil {
   4358 			if err != io.EOF {
   4359 				logError(testName, function, args, startTime, "", "CopyN failed", err)
   4360 				return
   4361 			}
   4362 		}
   4363 		if !bytes.Equal(buf[start:end], buffer.Bytes()) {
   4364 			logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
   4365 			return
   4366 		}
   4367 	}
   4368 
   4369 	// Generic seek error for errors other than io.EOF
   4370 	seekErr := errors.New("seek error")
   4371 
   4372 	testCases := []struct {
   4373 		offset    int64
   4374 		whence    int
   4375 		pos       int64
   4376 		err       error
   4377 		shouldCmp bool
   4378 		start     int
   4379 		end       int
   4380 	}{
   4381 		// Start from offset 0, fetch data and compare
   4382 		{0, 0, 0, nil, true, 0, 0},
   4383 		// Start from offset 2048, fetch data and compare
   4384 		{2048, 0, 2048, nil, true, 2048, bufSize},
   4385 		// Start from offset larger than possible
   4386 		{int64(bufSize) + 1024, 0, 0, seekErr, false, 0, 0},
   4387 		// Move to offset 0 without comparing
   4388 		{0, 0, 0, nil, false, 0, 0},
   4389 		// Move one step forward and compare
   4390 		{1, 1, 1, nil, true, 1, bufSize},
   4391 		// Move larger than possible
   4392 		{int64(bufSize), 1, 0, seekErr, false, 0, 0},
   4393 		// Provide negative offset with CUR_SEEK
   4394 		{int64(-1), 1, 0, seekErr, false, 0, 0},
   4395 		// Test with whence SEEK_END and with positive offset
   4396 		{1024, 2, int64(bufSize) - 1024, io.EOF, true, 0, 0},
   4397 		// Test with whence SEEK_END and with negative offset
   4398 		{-1024, 2, int64(bufSize) - 1024, nil, true, bufSize - 1024, bufSize},
   4399 		// Test with whence SEEK_END and with large negative offset
   4400 		{-int64(bufSize) * 2, 2, 0, seekErr, true, 0, 0},
   4401 	}
   4402 
   4403 	for i, testCase := range testCases {
   4404 		// Perform seek operation
   4405 		n, err := r.Seek(testCase.offset, testCase.whence)
   4406 		// We expect an error
   4407 		if testCase.err == seekErr && err == nil {
   4408 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", unexpected err value: expected: "+testCase.err.Error()+", found: "+err.Error(), err)
   4409 			return
   4410 		}
   4411 		// We expect a specific error
   4412 		if testCase.err != seekErr && testCase.err != err {
   4413 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", unexpected err value: expected: "+testCase.err.Error()+", found: "+err.Error(), err)
   4414 			return
   4415 		}
   4416 		// If we expect an error go to the next loop
   4417 		if testCase.err != nil {
   4418 			continue
   4419 		}
   4420 		// Check the returned seek pos
   4421 		if n != testCase.pos {
   4422 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", number of bytes seeked does not match, expected "+string(testCase.pos)+", got "+string(n), err)
   4423 			return
   4424 		}
   4425 		// Compare only if shouldCmp is activated
   4426 		if testCase.shouldCmp {
   4427 			cmpData(r, testCase.start, testCase.end)
   4428 		}
   4429 	}
   4430 	successLogger(testName, function, args, startTime).Info()
   4431 }
   4432 
   4433 // Tests get object ReaderAt interface methods.
   4434 func testGetObjectReadAtFunctional() {
   4435 	// initialize logging params
   4436 	startTime := time.Now()
   4437 	testName := getFuncName()
   4438 	function := "GetObject(bucketName, objectName)"
   4439 	args := map[string]interface{}{}
   4440 
   4441 	// Seed random based on current time.
   4442 	rand.Seed(time.Now().Unix())
   4443 
   4444 	// Instantiate new minio client object.
   4445 	c, err := minio.New(os.Getenv(serverEndpoint),
   4446 		&minio.Options{
   4447 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4448 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4449 		})
   4450 	if err != nil {
   4451 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4452 		return
   4453 	}
   4454 
   4455 	// Enable tracing, write to stderr.
   4456 	// c.TraceOn(os.Stderr)
   4457 
   4458 	// Set user agent.
   4459 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4460 
   4461 	// Generate a new random bucket name.
   4462 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4463 	args["bucketName"] = bucketName
   4464 
   4465 	// Make a new bucket.
   4466 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4467 	if err != nil {
   4468 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4469 		return
   4470 	}
   4471 
   4472 	defer cleanupBucket(bucketName, c)
   4473 
   4474 	// Generate 33K of data.
   4475 	bufSize := dataFileMap["datafile-33-kB"]
   4476 	reader := getDataReader("datafile-33-kB")
   4477 	defer reader.Close()
   4478 
   4479 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4480 	args["objectName"] = objectName
   4481 
   4482 	buf, err := io.ReadAll(reader)
   4483 	if err != nil {
   4484 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   4485 		return
   4486 	}
   4487 
   4488 	// Save the data
   4489 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4490 	if err != nil {
   4491 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4492 		return
   4493 	}
   4494 
   4495 	// read the data back
   4496 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   4497 	if err != nil {
   4498 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4499 		return
   4500 	}
   4501 	offset := int64(2048)
   4502 
   4503 	// read directly
   4504 	buf1 := make([]byte, 512)
   4505 	buf2 := make([]byte, 512)
   4506 	buf3 := make([]byte, 512)
   4507 	buf4 := make([]byte, 512)
   4508 
   4509 	// Test readAt before stat is called such that objectInfo doesn't change.
   4510 	m, err := r.ReadAt(buf1, offset)
   4511 	if err != nil {
   4512 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4513 		return
   4514 	}
   4515 	if m != len(buf1) {
   4516 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf1))+", got "+string(m), err)
   4517 		return
   4518 	}
   4519 	if !bytes.Equal(buf1, buf[offset:offset+512]) {
   4520 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   4521 		return
   4522 	}
   4523 	offset += 512
   4524 
   4525 	st, err := r.Stat()
   4526 	if err != nil {
   4527 		logError(testName, function, args, startTime, "", "Stat failed", err)
   4528 		return
   4529 	}
   4530 
   4531 	if st.Size != int64(bufSize) {
   4532 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   4533 		return
   4534 	}
   4535 
   4536 	m, err = r.ReadAt(buf2, offset)
   4537 	if err != nil {
   4538 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4539 		return
   4540 	}
   4541 	if m != len(buf2) {
   4542 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+", got "+string(m), err)
   4543 		return
   4544 	}
   4545 	if !bytes.Equal(buf2, buf[offset:offset+512]) {
   4546 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   4547 		return
   4548 	}
   4549 
   4550 	offset += 512
   4551 	m, err = r.ReadAt(buf3, offset)
   4552 	if err != nil {
   4553 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4554 		return
   4555 	}
   4556 	if m != len(buf3) {
   4557 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+", got "+string(m), err)
   4558 		return
   4559 	}
   4560 	if !bytes.Equal(buf3, buf[offset:offset+512]) {
   4561 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   4562 		return
   4563 	}
   4564 	offset += 512
   4565 	m, err = r.ReadAt(buf4, offset)
   4566 	if err != nil {
   4567 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4568 		return
   4569 	}
   4570 	if m != len(buf4) {
   4571 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+", got "+string(m), err)
   4572 		return
   4573 	}
   4574 	if !bytes.Equal(buf4, buf[offset:offset+512]) {
   4575 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   4576 		return
   4577 	}
   4578 
   4579 	buf5 := make([]byte, len(buf))
   4580 	// Read the whole object.
   4581 	m, err = r.ReadAt(buf5, 0)
   4582 	if err != nil {
   4583 		if err != io.EOF {
   4584 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4585 			return
   4586 		}
   4587 	}
   4588 	if m != len(buf5) {
   4589 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+", got "+string(m), err)
   4590 		return
   4591 	}
   4592 	if !bytes.Equal(buf, buf5) {
   4593 		logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
   4594 		return
   4595 	}
   4596 
   4597 	buf6 := make([]byte, len(buf)+1)
   4598 	// Read the whole object and beyond.
   4599 	_, err = r.ReadAt(buf6, 0)
   4600 	if err != nil {
   4601 		if err != io.EOF {
   4602 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4603 			return
   4604 		}
   4605 	}
   4606 
   4607 	successLogger(testName, function, args, startTime).Info()
   4608 }
   4609 
   4610 // Reproduces issue https://github.com/minio/minio-go/issues/1137
   4611 func testGetObjectReadAtWhenEOFWasReached() {
   4612 	// initialize logging params
   4613 	startTime := time.Now()
   4614 	testName := getFuncName()
   4615 	function := "GetObject(bucketName, objectName)"
   4616 	args := map[string]interface{}{}
   4617 
   4618 	// Seed random based on current time.
   4619 	rand.Seed(time.Now().Unix())
   4620 
   4621 	// Instantiate new minio client object.
   4622 	c, err := minio.New(os.Getenv(serverEndpoint),
   4623 		&minio.Options{
   4624 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4625 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4626 		})
   4627 	if err != nil {
   4628 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4629 		return
   4630 	}
   4631 
   4632 	// Enable tracing, write to stderr.
   4633 	// c.TraceOn(os.Stderr)
   4634 
   4635 	// Set user agent.
   4636 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4637 
   4638 	// Generate a new random bucket name.
   4639 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4640 	args["bucketName"] = bucketName
   4641 
   4642 	// Make a new bucket.
   4643 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4644 	if err != nil {
   4645 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4646 		return
   4647 	}
   4648 
   4649 	defer cleanupBucket(bucketName, c)
   4650 
   4651 	// Generate 33K of data.
   4652 	bufSize := dataFileMap["datafile-33-kB"]
   4653 	reader := getDataReader("datafile-33-kB")
   4654 	defer reader.Close()
   4655 
   4656 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4657 	args["objectName"] = objectName
   4658 
   4659 	buf, err := io.ReadAll(reader)
   4660 	if err != nil {
   4661 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   4662 		return
   4663 	}
   4664 
   4665 	// Save the data
   4666 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4667 	if err != nil {
   4668 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4669 		return
   4670 	}
   4671 
   4672 	// read the data back
   4673 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   4674 	if err != nil {
   4675 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4676 		return
   4677 	}
   4678 
   4679 	// read directly
   4680 	buf1 := make([]byte, len(buf))
   4681 	buf2 := make([]byte, 512)
   4682 
   4683 	m, err := r.Read(buf1)
   4684 	if err != nil {
   4685 		if err != io.EOF {
   4686 			logError(testName, function, args, startTime, "", "Read failed", err)
   4687 			return
   4688 		}
   4689 	}
   4690 	if m != len(buf1) {
   4691 		logError(testName, function, args, startTime, "", "Read read shorter bytes before reaching EOF, expected "+string(len(buf1))+", got "+string(m), err)
   4692 		return
   4693 	}
   4694 	if !bytes.Equal(buf1, buf) {
   4695 		logError(testName, function, args, startTime, "", "Incorrect count of Read data", err)
   4696 		return
   4697 	}
   4698 
   4699 	st, err := r.Stat()
   4700 	if err != nil {
   4701 		logError(testName, function, args, startTime, "", "Stat failed", err)
   4702 		return
   4703 	}
   4704 
   4705 	if st.Size != int64(bufSize) {
   4706 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   4707 		return
   4708 	}
   4709 
   4710 	m, err = r.ReadAt(buf2, 512)
   4711 	if err != nil {
   4712 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   4713 		return
   4714 	}
   4715 	if m != len(buf2) {
   4716 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+", got "+string(m), err)
   4717 		return
   4718 	}
   4719 	if !bytes.Equal(buf2, buf[512:1024]) {
   4720 		logError(testName, function, args, startTime, "", "Incorrect count of ReadAt data", err)
   4721 		return
   4722 	}
   4723 
   4724 	successLogger(testName, function, args, startTime).Info()
   4725 }
   4726 
   4727 // Test Presigned Post Policy
   4728 func testPresignedPostPolicy() {
   4729 	// initialize logging params
   4730 	startTime := time.Now()
   4731 	testName := getFuncName()
   4732 	function := "PresignedPostPolicy(policy)"
   4733 	args := map[string]interface{}{
   4734 		"policy": "",
   4735 	}
   4736 
   4737 	// Seed random based on current time.
   4738 	rand.Seed(time.Now().Unix())
   4739 
   4740 	// Instantiate new minio client object
   4741 	c, err := minio.New(os.Getenv(serverEndpoint),
   4742 		&minio.Options{
   4743 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4744 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4745 		})
   4746 	if err != nil {
   4747 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4748 		return
   4749 	}
   4750 
   4751 	// Enable tracing, write to stderr.
   4752 	// c.TraceOn(os.Stderr)
   4753 
   4754 	// Set user agent.
   4755 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4756 
   4757 	// Generate a new random bucket name.
   4758 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4759 
   4760 	// Make a new bucket in 'us-east-1' (source bucket).
   4761 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4762 	if err != nil {
   4763 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4764 		return
   4765 	}
   4766 
   4767 	defer cleanupBucket(bucketName, c)
   4768 
   4769 	// Generate 33K of data.
   4770 	reader := getDataReader("datafile-33-kB")
   4771 	defer reader.Close()
   4772 
   4773 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4774 	// Azure requires the key to not start with a number
   4775 	metadataKey := randString(60, rand.NewSource(time.Now().UnixNano()), "user")
   4776 	metadataValue := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4777 
   4778 	buf, err := io.ReadAll(reader)
   4779 	if err != nil {
   4780 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   4781 		return
   4782 	}
   4783 
   4784 	// Save the data
   4785 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4786 	if err != nil {
   4787 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4788 		return
   4789 	}
   4790 
   4791 	policy := minio.NewPostPolicy()
   4792 
   4793 	if err := policy.SetBucket(""); err == nil {
   4794 		logError(testName, function, args, startTime, "", "SetBucket did not fail for invalid conditions", err)
   4795 		return
   4796 	}
   4797 	if err := policy.SetKey(""); err == nil {
   4798 		logError(testName, function, args, startTime, "", "SetKey did not fail for invalid conditions", err)
   4799 		return
   4800 	}
   4801 	if err := policy.SetExpires(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)); err == nil {
   4802 		logError(testName, function, args, startTime, "", "SetExpires did not fail for invalid conditions", err)
   4803 		return
   4804 	}
   4805 	if err := policy.SetContentType(""); err == nil {
   4806 		logError(testName, function, args, startTime, "", "SetContentType did not fail for invalid conditions", err)
   4807 		return
   4808 	}
   4809 	if err := policy.SetContentLengthRange(1024*1024, 1024); err == nil {
   4810 		logError(testName, function, args, startTime, "", "SetContentLengthRange did not fail for invalid conditions", err)
   4811 		return
   4812 	}
   4813 	if err := policy.SetUserMetadata("", ""); err == nil {
   4814 		logError(testName, function, args, startTime, "", "SetUserMetadata did not fail for invalid conditions", err)
   4815 		return
   4816 	}
   4817 
   4818 	policy.SetBucket(bucketName)
   4819 	policy.SetKey(objectName)
   4820 	policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
   4821 	policy.SetContentType("binary/octet-stream")
   4822 	policy.SetContentLengthRange(10, 1024*1024)
   4823 	policy.SetUserMetadata(metadataKey, metadataValue)
   4824 	args["policy"] = policy.String()
   4825 
   4826 	presignedPostPolicyURL, formData, err := c.PresignedPostPolicy(context.Background(), policy)
   4827 	if err != nil {
   4828 		logError(testName, function, args, startTime, "", "PresignedPostPolicy failed", err)
   4829 		return
   4830 	}
   4831 
   4832 	var formBuf bytes.Buffer
   4833 	writer := multipart.NewWriter(&formBuf)
   4834 	for k, v := range formData {
   4835 		writer.WriteField(k, v)
   4836 	}
   4837 
   4838 	// Get a 33KB file to upload and test if set post policy works
   4839 	filePath := getMintDataDirFilePath("datafile-33-kB")
   4840 	if filePath == "" {
   4841 		// Make a temp file with 33 KB data.
   4842 		file, err := os.CreateTemp(os.TempDir(), "PresignedPostPolicyTest")
   4843 		if err != nil {
   4844 			logError(testName, function, args, startTime, "", "TempFile creation failed", err)
   4845 			return
   4846 		}
   4847 		if _, err = io.Copy(file, getDataReader("datafile-33-kB")); err != nil {
   4848 			logError(testName, function, args, startTime, "", "Copy failed", err)
   4849 			return
   4850 		}
   4851 		if err = file.Close(); err != nil {
   4852 			logError(testName, function, args, startTime, "", "File Close failed", err)
   4853 			return
   4854 		}
   4855 		filePath = file.Name()
   4856 	}
   4857 
   4858 	// add file to post request
   4859 	f, err := os.Open(filePath)
   4860 	defer f.Close()
   4861 	if err != nil {
   4862 		logError(testName, function, args, startTime, "", "File open failed", err)
   4863 		return
   4864 	}
   4865 	w, err := writer.CreateFormFile("file", filePath)
   4866 	if err != nil {
   4867 		logError(testName, function, args, startTime, "", "CreateFormFile failed", err)
   4868 		return
   4869 	}
   4870 
   4871 	_, err = io.Copy(w, f)
   4872 	if err != nil {
   4873 		logError(testName, function, args, startTime, "", "Copy failed", err)
   4874 		return
   4875 	}
   4876 	writer.Close()
   4877 
   4878 	transport, err := minio.DefaultTransport(mustParseBool(os.Getenv(enableHTTPS)))
   4879 	if err != nil {
   4880 		logError(testName, function, args, startTime, "", "DefaultTransport failed", err)
   4881 		return
   4882 	}
   4883 
   4884 	httpClient := &http.Client{
   4885 		// Setting a sensible time out of 30secs to wait for response
   4886 		// headers. Request is pro-actively canceled after 30secs
   4887 		// with no response.
   4888 		Timeout:   30 * time.Second,
   4889 		Transport: transport,
   4890 	}
   4891 
   4892 	req, err := http.NewRequest(http.MethodPost, presignedPostPolicyURL.String(), bytes.NewReader(formBuf.Bytes()))
   4893 	if err != nil {
   4894 		logError(testName, function, args, startTime, "", "Http request failed", err)
   4895 		return
   4896 	}
   4897 
   4898 	req.Header.Set("Content-Type", writer.FormDataContentType())
   4899 
   4900 	// make post request with correct form data
   4901 	res, err := httpClient.Do(req)
   4902 	if err != nil {
   4903 		logError(testName, function, args, startTime, "", "Http request failed", err)
   4904 		return
   4905 	}
   4906 	defer res.Body.Close()
   4907 	if res.StatusCode != http.StatusNoContent {
   4908 		logError(testName, function, args, startTime, "", "Http request failed", errors.New(res.Status))
   4909 		return
   4910 	}
   4911 
   4912 	// expected path should be absolute path of the object
   4913 	var scheme string
   4914 	if mustParseBool(os.Getenv(enableHTTPS)) {
   4915 		scheme = "https://"
   4916 	} else {
   4917 		scheme = "http://"
   4918 	}
   4919 
   4920 	expectedLocation := scheme + os.Getenv(serverEndpoint) + "/" + bucketName + "/" + objectName
   4921 	expectedLocationBucketDNS := scheme + bucketName + "." + os.Getenv(serverEndpoint) + "/" + objectName
   4922 
   4923 	if val, ok := res.Header["Location"]; ok {
   4924 		if val[0] != expectedLocation && val[0] != expectedLocationBucketDNS {
   4925 			logError(testName, function, args, startTime, "", "Location in header response is incorrect", err)
   4926 			return
   4927 		}
   4928 	} else {
   4929 		logError(testName, function, args, startTime, "", "Location not found in header response", err)
   4930 		return
   4931 	}
   4932 
   4933 	successLogger(testName, function, args, startTime).Info()
   4934 }
   4935 
   4936 // Tests copy object
   4937 func testCopyObject() {
   4938 	// initialize logging params
   4939 	startTime := time.Now()
   4940 	testName := getFuncName()
   4941 	function := "CopyObject(dst, src)"
   4942 	args := map[string]interface{}{}
   4943 
   4944 	// Seed random based on current time.
   4945 	rand.Seed(time.Now().Unix())
   4946 
   4947 	// Instantiate new minio client object
   4948 	c, err := minio.New(os.Getenv(serverEndpoint),
   4949 		&minio.Options{
   4950 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   4951 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   4952 		})
   4953 	if err != nil {
   4954 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   4955 		return
   4956 	}
   4957 
   4958 	// Enable tracing, write to stderr.
   4959 	// c.TraceOn(os.Stderr)
   4960 
   4961 	// Set user agent.
   4962 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   4963 
   4964 	// Generate a new random bucket name.
   4965 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   4966 
   4967 	// Make a new bucket in 'us-east-1' (source bucket).
   4968 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   4969 	if err != nil {
   4970 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4971 		return
   4972 	}
   4973 
   4974 	defer cleanupBucket(bucketName, c)
   4975 
   4976 	// Make a new bucket in 'us-east-1' (destination bucket).
   4977 	err = c.MakeBucket(context.Background(), bucketName+"-copy", minio.MakeBucketOptions{Region: "us-east-1"})
   4978 	if err != nil {
   4979 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   4980 		return
   4981 	}
   4982 	defer cleanupBucket(bucketName+"-copy", c)
   4983 
   4984 	// Generate 33K of data.
   4985 	bufSize := dataFileMap["datafile-33-kB"]
   4986 	reader := getDataReader("datafile-33-kB")
   4987 
   4988 	// Save the data
   4989 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   4990 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   4991 	if err != nil {
   4992 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   4993 		return
   4994 	}
   4995 
   4996 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   4997 	if err != nil {
   4998 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   4999 		return
   5000 	}
   5001 	// Check the various fields of source object against destination object.
   5002 	objInfo, err := r.Stat()
   5003 	if err != nil {
   5004 		logError(testName, function, args, startTime, "", "Stat failed", err)
   5005 		return
   5006 	}
   5007 
   5008 	// Copy Source
   5009 	src := minio.CopySrcOptions{
   5010 		Bucket: bucketName,
   5011 		Object: objectName,
   5012 		// Set copy conditions.
   5013 		MatchETag:          objInfo.ETag,
   5014 		MatchModifiedSince: time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC),
   5015 	}
   5016 	args["src"] = src
   5017 
   5018 	dst := minio.CopyDestOptions{
   5019 		Bucket: bucketName + "-copy",
   5020 		Object: objectName + "-copy",
   5021 	}
   5022 
   5023 	// Perform the Copy
   5024 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
   5025 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
   5026 		return
   5027 	}
   5028 
   5029 	// Source object
   5030 	r, err = c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   5031 	if err != nil {
   5032 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   5033 		return
   5034 	}
   5035 
   5036 	// Destination object
   5037 	readerCopy, err := c.GetObject(context.Background(), bucketName+"-copy", objectName+"-copy", minio.GetObjectOptions{})
   5038 	if err != nil {
   5039 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   5040 		return
   5041 	}
   5042 
   5043 	// Check the various fields of source object against destination object.
   5044 	objInfo, err = r.Stat()
   5045 	if err != nil {
   5046 		logError(testName, function, args, startTime, "", "Stat failed", err)
   5047 		return
   5048 	}
   5049 	objInfoCopy, err := readerCopy.Stat()
   5050 	if err != nil {
   5051 		logError(testName, function, args, startTime, "", "Stat failed", err)
   5052 		return
   5053 	}
   5054 	if objInfo.Size != objInfoCopy.Size {
   5055 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(objInfoCopy.Size)+", got "+string(objInfo.Size), err)
   5056 		return
   5057 	}
   5058 
   5059 	if err := crcMatchesName(r, "datafile-33-kB"); err != nil {
   5060 		logError(testName, function, args, startTime, "", "data CRC check failed", err)
   5061 		return
   5062 	}
   5063 	if err := crcMatchesName(readerCopy, "datafile-33-kB"); err != nil {
   5064 		logError(testName, function, args, startTime, "", "copy data CRC check failed", err)
   5065 		return
   5066 	}
   5067 	// Close all the get readers before proceeding with CopyObject operations.
   5068 	r.Close()
   5069 	readerCopy.Close()
   5070 
   5071 	// CopyObject again but with wrong conditions
   5072 	src = minio.CopySrcOptions{
   5073 		Bucket:               bucketName,
   5074 		Object:               objectName,
   5075 		MatchUnmodifiedSince: time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC),
   5076 		NoMatchETag:          objInfo.ETag,
   5077 	}
   5078 
   5079 	// Perform the Copy which should fail
   5080 	_, err = c.CopyObject(context.Background(), dst, src)
   5081 	if err == nil {
   5082 		logError(testName, function, args, startTime, "", "CopyObject did not fail for invalid conditions", err)
   5083 		return
   5084 	}
   5085 
   5086 	src = minio.CopySrcOptions{
   5087 		Bucket: bucketName,
   5088 		Object: objectName,
   5089 	}
   5090 
   5091 	dst = minio.CopyDestOptions{
   5092 		Bucket:          bucketName,
   5093 		Object:          objectName,
   5094 		ReplaceMetadata: true,
   5095 		UserMetadata: map[string]string{
   5096 			"Copy": "should be same",
   5097 		},
   5098 	}
   5099 	args["dst"] = dst
   5100 	args["src"] = src
   5101 
   5102 	_, err = c.CopyObject(context.Background(), dst, src)
   5103 	if err != nil {
   5104 		logError(testName, function, args, startTime, "", "CopyObject shouldn't fail", err)
   5105 		return
   5106 	}
   5107 
   5108 	oi, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
   5109 	if err != nil {
   5110 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   5111 		return
   5112 	}
   5113 
   5114 	stOpts := minio.StatObjectOptions{}
   5115 	stOpts.SetMatchETag(oi.ETag)
   5116 	objInfo, err = c.StatObject(context.Background(), bucketName, objectName, stOpts)
   5117 	if err != nil {
   5118 		logError(testName, function, args, startTime, "", "CopyObject ETag should match and not fail", err)
   5119 		return
   5120 	}
   5121 
   5122 	if objInfo.Metadata.Get("x-amz-meta-copy") != "should be same" {
   5123 		logError(testName, function, args, startTime, "", "CopyObject modified metadata should match", err)
   5124 		return
   5125 	}
   5126 
   5127 	successLogger(testName, function, args, startTime).Info()
   5128 }
   5129 
   5130 // Tests SSE-C get object ReaderSeeker interface methods.
   5131 func testSSECEncryptedGetObjectReadSeekFunctional() {
   5132 	// initialize logging params
   5133 	startTime := time.Now()
   5134 	testName := getFuncName()
   5135 	function := "GetObject(bucketName, objectName)"
   5136 	args := map[string]interface{}{}
   5137 
   5138 	// Seed random based on current time.
   5139 	rand.Seed(time.Now().Unix())
   5140 
   5141 	// Instantiate new minio client object.
   5142 	c, err := minio.New(os.Getenv(serverEndpoint),
   5143 		&minio.Options{
   5144 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5145 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5146 		})
   5147 	if err != nil {
   5148 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5149 		return
   5150 	}
   5151 
   5152 	// Enable tracing, write to stderr.
   5153 	// c.TraceOn(os.Stderr)
   5154 
   5155 	// Set user agent.
   5156 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5157 
   5158 	// Generate a new random bucket name.
   5159 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5160 	args["bucketName"] = bucketName
   5161 
   5162 	// Make a new bucket.
   5163 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   5164 	if err != nil {
   5165 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   5166 		return
   5167 	}
   5168 
   5169 	defer func() {
   5170 		// Delete all objects and buckets
   5171 		if err = cleanupBucket(bucketName, c); err != nil {
   5172 			logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   5173 			return
   5174 		}
   5175 	}()
   5176 
   5177 	// Generate 129MiB of data.
   5178 	bufSize := dataFileMap["datafile-129-MB"]
   5179 	reader := getDataReader("datafile-129-MB")
   5180 	defer reader.Close()
   5181 
   5182 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   5183 	args["objectName"] = objectName
   5184 
   5185 	buf, err := io.ReadAll(reader)
   5186 	if err != nil {
   5187 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   5188 		return
   5189 	}
   5190 
   5191 	// Save the data
   5192 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{
   5193 		ContentType:          "binary/octet-stream",
   5194 		ServerSideEncryption: encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+objectName)),
   5195 	})
   5196 	if err != nil {
   5197 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5198 		return
   5199 	}
   5200 
   5201 	// Read the data back
   5202 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{
   5203 		ServerSideEncryption: encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+objectName)),
   5204 	})
   5205 	if err != nil {
   5206 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   5207 		return
   5208 	}
   5209 	defer r.Close()
   5210 
   5211 	st, err := r.Stat()
   5212 	if err != nil {
   5213 		logError(testName, function, args, startTime, "", "Stat object failed", err)
   5214 		return
   5215 	}
   5216 
   5217 	if st.Size != int64(bufSize) {
   5218 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   5219 		return
   5220 	}
   5221 
   5222 	// This following function helps us to compare data from the reader after seek
   5223 	// with the data from the original buffer
   5224 	cmpData := func(r io.Reader, start, end int) {
   5225 		if end-start == 0 {
   5226 			return
   5227 		}
   5228 		buffer := bytes.NewBuffer([]byte{})
   5229 		if _, err := io.CopyN(buffer, r, int64(bufSize)); err != nil {
   5230 			if err != io.EOF {
   5231 				logError(testName, function, args, startTime, "", "CopyN failed", err)
   5232 				return
   5233 			}
   5234 		}
   5235 		if !bytes.Equal(buf[start:end], buffer.Bytes()) {
   5236 			logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
   5237 			return
   5238 		}
   5239 	}
   5240 
   5241 	testCases := []struct {
   5242 		offset    int64
   5243 		whence    int
   5244 		pos       int64
   5245 		err       error
   5246 		shouldCmp bool
   5247 		start     int
   5248 		end       int
   5249 	}{
   5250 		// Start from offset 0, fetch data and compare
   5251 		{0, 0, 0, nil, true, 0, 0},
   5252 		// Start from offset 2048, fetch data and compare
   5253 		{2048, 0, 2048, nil, true, 2048, bufSize},
   5254 		// Start from offset larger than possible
   5255 		{int64(bufSize) + 1024, 0, 0, io.EOF, false, 0, 0},
   5256 		// Move to offset 0 without comparing
   5257 		{0, 0, 0, nil, false, 0, 0},
   5258 		// Move one step forward and compare
   5259 		{1, 1, 1, nil, true, 1, bufSize},
   5260 		// Move larger than possible
   5261 		{int64(bufSize), 1, 0, io.EOF, false, 0, 0},
   5262 		// Provide negative offset with CUR_SEEK
   5263 		{int64(-1), 1, 0, fmt.Errorf("Negative position not allowed for 1"), false, 0, 0},
   5264 		// Test with whence SEEK_END and with positive offset
   5265 		{1024, 2, 0, io.EOF, false, 0, 0},
   5266 		// Test with whence SEEK_END and with negative offset
   5267 		{-1024, 2, int64(bufSize) - 1024, nil, true, bufSize - 1024, bufSize},
   5268 		// Test with whence SEEK_END and with large negative offset
   5269 		{-int64(bufSize) * 2, 2, 0, fmt.Errorf("Seeking at negative offset not allowed for 2"), false, 0, 0},
   5270 		// Test with invalid whence
   5271 		{0, 3, 0, fmt.Errorf("Invalid whence 3"), false, 0, 0},
   5272 	}
   5273 
   5274 	for i, testCase := range testCases {
   5275 		// Perform seek operation
   5276 		n, err := r.Seek(testCase.offset, testCase.whence)
   5277 		if err != nil && testCase.err == nil {
   5278 			// We expected success.
   5279 			logError(testName, function, args, startTime, "",
   5280 				fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5281 			return
   5282 		}
   5283 		if err == nil && testCase.err != nil {
   5284 			// We expected failure, but got success.
   5285 			logError(testName, function, args, startTime, "",
   5286 				fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5287 			return
   5288 		}
   5289 		if err != nil && testCase.err != nil {
   5290 			if err.Error() != testCase.err.Error() {
   5291 				// We expect a specific error
   5292 				logError(testName, function, args, startTime, "",
   5293 					fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5294 				return
   5295 			}
   5296 		}
   5297 		// Check the returned seek pos
   5298 		if n != testCase.pos {
   5299 			logError(testName, function, args, startTime, "",
   5300 				fmt.Sprintf("Test %d, number of bytes seeked does not match, expected %d, got %d", i+1, testCase.pos, n), err)
   5301 			return
   5302 		}
   5303 		// Compare only if shouldCmp is activated
   5304 		if testCase.shouldCmp {
   5305 			cmpData(r, testCase.start, testCase.end)
   5306 		}
   5307 	}
   5308 
   5309 	successLogger(testName, function, args, startTime).Info()
   5310 }
   5311 
   5312 // Tests SSE-S3 get object ReaderSeeker interface methods.
   5313 func testSSES3EncryptedGetObjectReadSeekFunctional() {
   5314 	// initialize logging params
   5315 	startTime := time.Now()
   5316 	testName := getFuncName()
   5317 	function := "GetObject(bucketName, objectName)"
   5318 	args := map[string]interface{}{}
   5319 
   5320 	// Seed random based on current time.
   5321 	rand.Seed(time.Now().Unix())
   5322 
   5323 	// Instantiate new minio client object.
   5324 	c, err := minio.New(os.Getenv(serverEndpoint),
   5325 		&minio.Options{
   5326 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5327 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5328 		})
   5329 	if err != nil {
   5330 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5331 		return
   5332 	}
   5333 
   5334 	// Enable tracing, write to stderr.
   5335 	// c.TraceOn(os.Stderr)
   5336 
   5337 	// Set user agent.
   5338 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5339 
   5340 	// Generate a new random bucket name.
   5341 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5342 	args["bucketName"] = bucketName
   5343 
   5344 	// Make a new bucket.
   5345 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   5346 	if err != nil {
   5347 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   5348 		return
   5349 	}
   5350 
   5351 	defer func() {
   5352 		// Delete all objects and buckets
   5353 		if err = cleanupBucket(bucketName, c); err != nil {
   5354 			logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   5355 			return
   5356 		}
   5357 	}()
   5358 
   5359 	// Generate 129MiB of data.
   5360 	bufSize := dataFileMap["datafile-129-MB"]
   5361 	reader := getDataReader("datafile-129-MB")
   5362 	defer reader.Close()
   5363 
   5364 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   5365 	args["objectName"] = objectName
   5366 
   5367 	buf, err := io.ReadAll(reader)
   5368 	if err != nil {
   5369 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   5370 		return
   5371 	}
   5372 
   5373 	// Save the data
   5374 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{
   5375 		ContentType:          "binary/octet-stream",
   5376 		ServerSideEncryption: encrypt.NewSSE(),
   5377 	})
   5378 	if err != nil {
   5379 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5380 		return
   5381 	}
   5382 
   5383 	// Read the data back
   5384 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   5385 	if err != nil {
   5386 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   5387 		return
   5388 	}
   5389 	defer r.Close()
   5390 
   5391 	st, err := r.Stat()
   5392 	if err != nil {
   5393 		logError(testName, function, args, startTime, "", "Stat object failed", err)
   5394 		return
   5395 	}
   5396 
   5397 	if st.Size != int64(bufSize) {
   5398 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   5399 		return
   5400 	}
   5401 
   5402 	// This following function helps us to compare data from the reader after seek
   5403 	// with the data from the original buffer
   5404 	cmpData := func(r io.Reader, start, end int) {
   5405 		if end-start == 0 {
   5406 			return
   5407 		}
   5408 		buffer := bytes.NewBuffer([]byte{})
   5409 		if _, err := io.CopyN(buffer, r, int64(bufSize)); err != nil {
   5410 			if err != io.EOF {
   5411 				logError(testName, function, args, startTime, "", "CopyN failed", err)
   5412 				return
   5413 			}
   5414 		}
   5415 		if !bytes.Equal(buf[start:end], buffer.Bytes()) {
   5416 			logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
   5417 			return
   5418 		}
   5419 	}
   5420 
   5421 	testCases := []struct {
   5422 		offset    int64
   5423 		whence    int
   5424 		pos       int64
   5425 		err       error
   5426 		shouldCmp bool
   5427 		start     int
   5428 		end       int
   5429 	}{
   5430 		// Start from offset 0, fetch data and compare
   5431 		{0, 0, 0, nil, true, 0, 0},
   5432 		// Start from offset 2048, fetch data and compare
   5433 		{2048, 0, 2048, nil, true, 2048, bufSize},
   5434 		// Start from offset larger than possible
   5435 		{int64(bufSize) + 1024, 0, 0, io.EOF, false, 0, 0},
   5436 		// Move to offset 0 without comparing
   5437 		{0, 0, 0, nil, false, 0, 0},
   5438 		// Move one step forward and compare
   5439 		{1, 1, 1, nil, true, 1, bufSize},
   5440 		// Move larger than possible
   5441 		{int64(bufSize), 1, 0, io.EOF, false, 0, 0},
   5442 		// Provide negative offset with CUR_SEEK
   5443 		{int64(-1), 1, 0, fmt.Errorf("Negative position not allowed for 1"), false, 0, 0},
   5444 		// Test with whence SEEK_END and with positive offset
   5445 		{1024, 2, 0, io.EOF, false, 0, 0},
   5446 		// Test with whence SEEK_END and with negative offset
   5447 		{-1024, 2, int64(bufSize) - 1024, nil, true, bufSize - 1024, bufSize},
   5448 		// Test with whence SEEK_END and with large negative offset
   5449 		{-int64(bufSize) * 2, 2, 0, fmt.Errorf("Seeking at negative offset not allowed for 2"), false, 0, 0},
   5450 		// Test with invalid whence
   5451 		{0, 3, 0, fmt.Errorf("Invalid whence 3"), false, 0, 0},
   5452 	}
   5453 
   5454 	for i, testCase := range testCases {
   5455 		// Perform seek operation
   5456 		n, err := r.Seek(testCase.offset, testCase.whence)
   5457 		if err != nil && testCase.err == nil {
   5458 			// We expected success.
   5459 			logError(testName, function, args, startTime, "",
   5460 				fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5461 			return
   5462 		}
   5463 		if err == nil && testCase.err != nil {
   5464 			// We expected failure, but got success.
   5465 			logError(testName, function, args, startTime, "",
   5466 				fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5467 			return
   5468 		}
   5469 		if err != nil && testCase.err != nil {
   5470 			if err.Error() != testCase.err.Error() {
   5471 				// We expect a specific error
   5472 				logError(testName, function, args, startTime, "",
   5473 					fmt.Sprintf("Test %d, unexpected err value: expected: %s, found: %s", i+1, testCase.err, err), err)
   5474 				return
   5475 			}
   5476 		}
   5477 		// Check the returned seek pos
   5478 		if n != testCase.pos {
   5479 			logError(testName, function, args, startTime, "",
   5480 				fmt.Sprintf("Test %d, number of bytes seeked does not match, expected %d, got %d", i+1, testCase.pos, n), err)
   5481 			return
   5482 		}
   5483 		// Compare only if shouldCmp is activated
   5484 		if testCase.shouldCmp {
   5485 			cmpData(r, testCase.start, testCase.end)
   5486 		}
   5487 	}
   5488 
   5489 	successLogger(testName, function, args, startTime).Info()
   5490 }
   5491 
   5492 // Tests SSE-C get object ReaderAt interface methods.
   5493 func testSSECEncryptedGetObjectReadAtFunctional() {
   5494 	// initialize logging params
   5495 	startTime := time.Now()
   5496 	testName := getFuncName()
   5497 	function := "GetObject(bucketName, objectName)"
   5498 	args := map[string]interface{}{}
   5499 
   5500 	// Seed random based on current time.
   5501 	rand.Seed(time.Now().Unix())
   5502 
   5503 	// Instantiate new minio client object.
   5504 	c, err := minio.New(os.Getenv(serverEndpoint),
   5505 		&minio.Options{
   5506 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5507 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5508 		})
   5509 	if err != nil {
   5510 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5511 		return
   5512 	}
   5513 
   5514 	// Enable tracing, write to stderr.
   5515 	// c.TraceOn(os.Stderr)
   5516 
   5517 	// Set user agent.
   5518 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5519 
   5520 	// Generate a new random bucket name.
   5521 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5522 	args["bucketName"] = bucketName
   5523 
   5524 	// Make a new bucket.
   5525 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   5526 	if err != nil {
   5527 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   5528 		return
   5529 	}
   5530 
   5531 	defer cleanupBucket(bucketName, c)
   5532 
   5533 	// Generate 129MiB of data.
   5534 	bufSize := dataFileMap["datafile-129-MB"]
   5535 	reader := getDataReader("datafile-129-MB")
   5536 	defer reader.Close()
   5537 
   5538 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   5539 	args["objectName"] = objectName
   5540 
   5541 	buf, err := io.ReadAll(reader)
   5542 	if err != nil {
   5543 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   5544 		return
   5545 	}
   5546 
   5547 	// Save the data
   5548 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{
   5549 		ContentType:          "binary/octet-stream",
   5550 		ServerSideEncryption: encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+objectName)),
   5551 	})
   5552 	if err != nil {
   5553 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5554 		return
   5555 	}
   5556 
   5557 	// read the data back
   5558 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{
   5559 		ServerSideEncryption: encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+objectName)),
   5560 	})
   5561 	if err != nil {
   5562 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5563 		return
   5564 	}
   5565 	defer r.Close()
   5566 
   5567 	offset := int64(2048)
   5568 
   5569 	// read directly
   5570 	buf1 := make([]byte, 512)
   5571 	buf2 := make([]byte, 512)
   5572 	buf3 := make([]byte, 512)
   5573 	buf4 := make([]byte, 512)
   5574 
   5575 	// Test readAt before stat is called such that objectInfo doesn't change.
   5576 	m, err := r.ReadAt(buf1, offset)
   5577 	if err != nil {
   5578 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5579 		return
   5580 	}
   5581 	if m != len(buf1) {
   5582 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf1))+", got "+string(m), err)
   5583 		return
   5584 	}
   5585 	if !bytes.Equal(buf1, buf[offset:offset+512]) {
   5586 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5587 		return
   5588 	}
   5589 	offset += 512
   5590 
   5591 	st, err := r.Stat()
   5592 	if err != nil {
   5593 		logError(testName, function, args, startTime, "", "Stat failed", err)
   5594 		return
   5595 	}
   5596 
   5597 	if st.Size != int64(bufSize) {
   5598 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   5599 		return
   5600 	}
   5601 
   5602 	m, err = r.ReadAt(buf2, offset)
   5603 	if err != nil {
   5604 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5605 		return
   5606 	}
   5607 	if m != len(buf2) {
   5608 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+", got "+string(m), err)
   5609 		return
   5610 	}
   5611 	if !bytes.Equal(buf2, buf[offset:offset+512]) {
   5612 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5613 		return
   5614 	}
   5615 	offset += 512
   5616 	m, err = r.ReadAt(buf3, offset)
   5617 	if err != nil {
   5618 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5619 		return
   5620 	}
   5621 	if m != len(buf3) {
   5622 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+", got "+string(m), err)
   5623 		return
   5624 	}
   5625 	if !bytes.Equal(buf3, buf[offset:offset+512]) {
   5626 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5627 		return
   5628 	}
   5629 	offset += 512
   5630 	m, err = r.ReadAt(buf4, offset)
   5631 	if err != nil {
   5632 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5633 		return
   5634 	}
   5635 	if m != len(buf4) {
   5636 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+", got "+string(m), err)
   5637 		return
   5638 	}
   5639 	if !bytes.Equal(buf4, buf[offset:offset+512]) {
   5640 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5641 		return
   5642 	}
   5643 
   5644 	buf5 := make([]byte, len(buf))
   5645 	// Read the whole object.
   5646 	m, err = r.ReadAt(buf5, 0)
   5647 	if err != nil {
   5648 		if err != io.EOF {
   5649 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5650 			return
   5651 		}
   5652 	}
   5653 	if m != len(buf5) {
   5654 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+", got "+string(m), err)
   5655 		return
   5656 	}
   5657 	if !bytes.Equal(buf, buf5) {
   5658 		logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
   5659 		return
   5660 	}
   5661 
   5662 	buf6 := make([]byte, len(buf)+1)
   5663 	// Read the whole object and beyond.
   5664 	_, err = r.ReadAt(buf6, 0)
   5665 	if err != nil {
   5666 		if err != io.EOF {
   5667 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5668 			return
   5669 		}
   5670 	}
   5671 
   5672 	successLogger(testName, function, args, startTime).Info()
   5673 }
   5674 
   5675 // Tests SSE-S3 get object ReaderAt interface methods.
   5676 func testSSES3EncryptedGetObjectReadAtFunctional() {
   5677 	// initialize logging params
   5678 	startTime := time.Now()
   5679 	testName := getFuncName()
   5680 	function := "GetObject(bucketName, objectName)"
   5681 	args := map[string]interface{}{}
   5682 
   5683 	// Seed random based on current time.
   5684 	rand.Seed(time.Now().Unix())
   5685 
   5686 	// Instantiate new minio client object.
   5687 	c, err := minio.New(os.Getenv(serverEndpoint),
   5688 		&minio.Options{
   5689 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5690 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5691 		})
   5692 	if err != nil {
   5693 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5694 		return
   5695 	}
   5696 
   5697 	// Enable tracing, write to stderr.
   5698 	// c.TraceOn(os.Stderr)
   5699 
   5700 	// Set user agent.
   5701 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5702 
   5703 	// Generate a new random bucket name.
   5704 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5705 	args["bucketName"] = bucketName
   5706 
   5707 	// Make a new bucket.
   5708 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   5709 	if err != nil {
   5710 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   5711 		return
   5712 	}
   5713 
   5714 	defer cleanupBucket(bucketName, c)
   5715 
   5716 	// Generate 129MiB of data.
   5717 	bufSize := dataFileMap["datafile-129-MB"]
   5718 	reader := getDataReader("datafile-129-MB")
   5719 	defer reader.Close()
   5720 
   5721 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   5722 	args["objectName"] = objectName
   5723 
   5724 	buf, err := io.ReadAll(reader)
   5725 	if err != nil {
   5726 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   5727 		return
   5728 	}
   5729 
   5730 	// Save the data
   5731 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{
   5732 		ContentType:          "binary/octet-stream",
   5733 		ServerSideEncryption: encrypt.NewSSE(),
   5734 	})
   5735 	if err != nil {
   5736 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5737 		return
   5738 	}
   5739 
   5740 	// read the data back
   5741 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   5742 	if err != nil {
   5743 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   5744 		return
   5745 	}
   5746 	defer r.Close()
   5747 
   5748 	offset := int64(2048)
   5749 
   5750 	// read directly
   5751 	buf1 := make([]byte, 512)
   5752 	buf2 := make([]byte, 512)
   5753 	buf3 := make([]byte, 512)
   5754 	buf4 := make([]byte, 512)
   5755 
   5756 	// Test readAt before stat is called such that objectInfo doesn't change.
   5757 	m, err := r.ReadAt(buf1, offset)
   5758 	if err != nil {
   5759 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5760 		return
   5761 	}
   5762 	if m != len(buf1) {
   5763 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf1))+", got "+string(m), err)
   5764 		return
   5765 	}
   5766 	if !bytes.Equal(buf1, buf[offset:offset+512]) {
   5767 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5768 		return
   5769 	}
   5770 	offset += 512
   5771 
   5772 	st, err := r.Stat()
   5773 	if err != nil {
   5774 		logError(testName, function, args, startTime, "", "Stat failed", err)
   5775 		return
   5776 	}
   5777 
   5778 	if st.Size != int64(bufSize) {
   5779 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
   5780 		return
   5781 	}
   5782 
   5783 	m, err = r.ReadAt(buf2, offset)
   5784 	if err != nil {
   5785 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5786 		return
   5787 	}
   5788 	if m != len(buf2) {
   5789 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+", got "+string(m), err)
   5790 		return
   5791 	}
   5792 	if !bytes.Equal(buf2, buf[offset:offset+512]) {
   5793 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5794 		return
   5795 	}
   5796 	offset += 512
   5797 	m, err = r.ReadAt(buf3, offset)
   5798 	if err != nil {
   5799 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5800 		return
   5801 	}
   5802 	if m != len(buf3) {
   5803 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+", got "+string(m), err)
   5804 		return
   5805 	}
   5806 	if !bytes.Equal(buf3, buf[offset:offset+512]) {
   5807 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5808 		return
   5809 	}
   5810 	offset += 512
   5811 	m, err = r.ReadAt(buf4, offset)
   5812 	if err != nil {
   5813 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5814 		return
   5815 	}
   5816 	if m != len(buf4) {
   5817 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+", got "+string(m), err)
   5818 		return
   5819 	}
   5820 	if !bytes.Equal(buf4, buf[offset:offset+512]) {
   5821 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   5822 		return
   5823 	}
   5824 
   5825 	buf5 := make([]byte, len(buf))
   5826 	// Read the whole object.
   5827 	m, err = r.ReadAt(buf5, 0)
   5828 	if err != nil {
   5829 		if err != io.EOF {
   5830 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5831 			return
   5832 		}
   5833 	}
   5834 	if m != len(buf5) {
   5835 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+", got "+string(m), err)
   5836 		return
   5837 	}
   5838 	if !bytes.Equal(buf, buf5) {
   5839 		logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
   5840 		return
   5841 	}
   5842 
   5843 	buf6 := make([]byte, len(buf)+1)
   5844 	// Read the whole object and beyond.
   5845 	_, err = r.ReadAt(buf6, 0)
   5846 	if err != nil {
   5847 		if err != io.EOF {
   5848 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   5849 			return
   5850 		}
   5851 	}
   5852 
   5853 	successLogger(testName, function, args, startTime).Info()
   5854 }
   5855 
   5856 // testSSECEncryptionPutGet tests encryption with customer provided encryption keys
   5857 func testSSECEncryptionPutGet() {
   5858 	// initialize logging params
   5859 	startTime := time.Now()
   5860 	testName := getFuncName()
   5861 	function := "PutEncryptedObject(bucketName, objectName, reader, sse)"
   5862 	args := map[string]interface{}{
   5863 		"bucketName": "",
   5864 		"objectName": "",
   5865 		"sse":        "",
   5866 	}
   5867 	// Seed random based on current time.
   5868 	rand.Seed(time.Now().Unix())
   5869 
   5870 	// Instantiate new minio client object
   5871 	c, err := minio.New(os.Getenv(serverEndpoint),
   5872 		&minio.Options{
   5873 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5874 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5875 		})
   5876 	if err != nil {
   5877 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5878 		return
   5879 	}
   5880 
   5881 	// Enable tracing, write to stderr.
   5882 	// c.TraceOn(os.Stderr)
   5883 
   5884 	// Set user agent.
   5885 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5886 
   5887 	// Generate a new random bucket name.
   5888 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5889 	args["bucketName"] = bucketName
   5890 
   5891 	// Make a new bucket.
   5892 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   5893 	if err != nil {
   5894 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   5895 		return
   5896 	}
   5897 
   5898 	defer cleanupBucket(bucketName, c)
   5899 
   5900 	testCases := []struct {
   5901 		buf []byte
   5902 	}{
   5903 		{buf: bytes.Repeat([]byte("F"), 1)},
   5904 		{buf: bytes.Repeat([]byte("F"), 15)},
   5905 		{buf: bytes.Repeat([]byte("F"), 16)},
   5906 		{buf: bytes.Repeat([]byte("F"), 17)},
   5907 		{buf: bytes.Repeat([]byte("F"), 31)},
   5908 		{buf: bytes.Repeat([]byte("F"), 32)},
   5909 		{buf: bytes.Repeat([]byte("F"), 33)},
   5910 		{buf: bytes.Repeat([]byte("F"), 1024)},
   5911 		{buf: bytes.Repeat([]byte("F"), 1024*2)},
   5912 		{buf: bytes.Repeat([]byte("F"), 1024*1024)},
   5913 	}
   5914 
   5915 	const password = "correct horse battery staple" // https://xkcd.com/936/
   5916 
   5917 	for i, testCase := range testCases {
   5918 		// Generate a random object name
   5919 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   5920 		args["objectName"] = objectName
   5921 
   5922 		// Secured object
   5923 		sse := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   5924 		args["sse"] = sse
   5925 
   5926 		// Put encrypted data
   5927 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(testCase.buf), int64(len(testCase.buf)), minio.PutObjectOptions{ServerSideEncryption: sse})
   5928 		if err != nil {
   5929 			logError(testName, function, args, startTime, "", "PutEncryptedObject failed", err)
   5930 			return
   5931 		}
   5932 
   5933 		// Read the data back
   5934 		r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{ServerSideEncryption: sse})
   5935 		if err != nil {
   5936 			logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
   5937 			return
   5938 		}
   5939 		defer r.Close()
   5940 
   5941 		// Compare the sent object with the received one
   5942 		recvBuffer := bytes.NewBuffer([]byte{})
   5943 		if _, err = io.Copy(recvBuffer, r); err != nil {
   5944 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
   5945 			return
   5946 		}
   5947 		if recvBuffer.Len() != len(testCase.buf) {
   5948 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
   5949 			return
   5950 		}
   5951 		if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
   5952 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
   5953 			return
   5954 		}
   5955 
   5956 		successLogger(testName, function, args, startTime).Info()
   5957 
   5958 	}
   5959 
   5960 	successLogger(testName, function, args, startTime).Info()
   5961 }
   5962 
   5963 // TestEncryptionFPut tests encryption with customer specified encryption keys
   5964 func testSSECEncryptionFPut() {
   5965 	// initialize logging params
   5966 	startTime := time.Now()
   5967 	testName := getFuncName()
   5968 	function := "FPutEncryptedObject(bucketName, objectName, filePath, contentType, sse)"
   5969 	args := map[string]interface{}{
   5970 		"bucketName":  "",
   5971 		"objectName":  "",
   5972 		"filePath":    "",
   5973 		"contentType": "",
   5974 		"sse":         "",
   5975 	}
   5976 	// Seed random based on current time.
   5977 	rand.Seed(time.Now().Unix())
   5978 
   5979 	// Instantiate new minio client object
   5980 	c, err := minio.New(os.Getenv(serverEndpoint),
   5981 		&minio.Options{
   5982 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   5983 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   5984 		})
   5985 	if err != nil {
   5986 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   5987 		return
   5988 	}
   5989 
   5990 	// Enable tracing, write to stderr.
   5991 	// c.TraceOn(os.Stderr)
   5992 
   5993 	// Set user agent.
   5994 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   5995 
   5996 	// Generate a new random bucket name.
   5997 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   5998 	args["bucketName"] = bucketName
   5999 
   6000 	// Make a new bucket.
   6001 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   6002 	if err != nil {
   6003 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   6004 		return
   6005 	}
   6006 
   6007 	defer cleanupBucket(bucketName, c)
   6008 
   6009 	// Object custom metadata
   6010 	customContentType := "custom/contenttype"
   6011 	args["metadata"] = customContentType
   6012 
   6013 	testCases := []struct {
   6014 		buf []byte
   6015 	}{
   6016 		{buf: bytes.Repeat([]byte("F"), 0)},
   6017 		{buf: bytes.Repeat([]byte("F"), 1)},
   6018 		{buf: bytes.Repeat([]byte("F"), 15)},
   6019 		{buf: bytes.Repeat([]byte("F"), 16)},
   6020 		{buf: bytes.Repeat([]byte("F"), 17)},
   6021 		{buf: bytes.Repeat([]byte("F"), 31)},
   6022 		{buf: bytes.Repeat([]byte("F"), 32)},
   6023 		{buf: bytes.Repeat([]byte("F"), 33)},
   6024 		{buf: bytes.Repeat([]byte("F"), 1024)},
   6025 		{buf: bytes.Repeat([]byte("F"), 1024*2)},
   6026 		{buf: bytes.Repeat([]byte("F"), 1024*1024)},
   6027 	}
   6028 
   6029 	const password = "correct horse battery staple" // https://xkcd.com/936/
   6030 	for i, testCase := range testCases {
   6031 		// Generate a random object name
   6032 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6033 		args["objectName"] = objectName
   6034 
   6035 		// Secured object
   6036 		sse := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   6037 		args["sse"] = sse
   6038 
   6039 		// Generate a random file name.
   6040 		fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6041 		file, err := os.Create(fileName)
   6042 		if err != nil {
   6043 			logError(testName, function, args, startTime, "", "file create failed", err)
   6044 			return
   6045 		}
   6046 		_, err = file.Write(testCase.buf)
   6047 		if err != nil {
   6048 			logError(testName, function, args, startTime, "", "file write failed", err)
   6049 			return
   6050 		}
   6051 		file.Close()
   6052 		// Put encrypted data
   6053 		if _, err = c.FPutObject(context.Background(), bucketName, objectName, fileName, minio.PutObjectOptions{ServerSideEncryption: sse}); err != nil {
   6054 			logError(testName, function, args, startTime, "", "FPutEncryptedObject failed", err)
   6055 			return
   6056 		}
   6057 
   6058 		// Read the data back
   6059 		r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{ServerSideEncryption: sse})
   6060 		if err != nil {
   6061 			logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
   6062 			return
   6063 		}
   6064 		defer r.Close()
   6065 
   6066 		// Compare the sent object with the received one
   6067 		recvBuffer := bytes.NewBuffer([]byte{})
   6068 		if _, err = io.Copy(recvBuffer, r); err != nil {
   6069 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
   6070 			return
   6071 		}
   6072 		if recvBuffer.Len() != len(testCase.buf) {
   6073 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
   6074 			return
   6075 		}
   6076 		if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
   6077 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
   6078 			return
   6079 		}
   6080 
   6081 		os.Remove(fileName)
   6082 	}
   6083 
   6084 	successLogger(testName, function, args, startTime).Info()
   6085 }
   6086 
   6087 // testSSES3EncryptionPutGet tests SSE-S3 encryption
   6088 func testSSES3EncryptionPutGet() {
   6089 	// initialize logging params
   6090 	startTime := time.Now()
   6091 	testName := getFuncName()
   6092 	function := "PutEncryptedObject(bucketName, objectName, reader, sse)"
   6093 	args := map[string]interface{}{
   6094 		"bucketName": "",
   6095 		"objectName": "",
   6096 		"sse":        "",
   6097 	}
   6098 	// Seed random based on current time.
   6099 	rand.Seed(time.Now().Unix())
   6100 
   6101 	// Instantiate new minio client object
   6102 	c, err := minio.New(os.Getenv(serverEndpoint),
   6103 		&minio.Options{
   6104 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   6105 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   6106 		})
   6107 	if err != nil {
   6108 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   6109 		return
   6110 	}
   6111 
   6112 	// Enable tracing, write to stderr.
   6113 	// c.TraceOn(os.Stderr)
   6114 
   6115 	// Set user agent.
   6116 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   6117 
   6118 	// Generate a new random bucket name.
   6119 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   6120 	args["bucketName"] = bucketName
   6121 
   6122 	// Make a new bucket.
   6123 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   6124 	if err != nil {
   6125 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   6126 		return
   6127 	}
   6128 
   6129 	defer cleanupBucket(bucketName, c)
   6130 
   6131 	testCases := []struct {
   6132 		buf []byte
   6133 	}{
   6134 		{buf: bytes.Repeat([]byte("F"), 1)},
   6135 		{buf: bytes.Repeat([]byte("F"), 15)},
   6136 		{buf: bytes.Repeat([]byte("F"), 16)},
   6137 		{buf: bytes.Repeat([]byte("F"), 17)},
   6138 		{buf: bytes.Repeat([]byte("F"), 31)},
   6139 		{buf: bytes.Repeat([]byte("F"), 32)},
   6140 		{buf: bytes.Repeat([]byte("F"), 33)},
   6141 		{buf: bytes.Repeat([]byte("F"), 1024)},
   6142 		{buf: bytes.Repeat([]byte("F"), 1024*2)},
   6143 		{buf: bytes.Repeat([]byte("F"), 1024*1024)},
   6144 	}
   6145 
   6146 	for i, testCase := range testCases {
   6147 		// Generate a random object name
   6148 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6149 		args["objectName"] = objectName
   6150 
   6151 		// Secured object
   6152 		sse := encrypt.NewSSE()
   6153 		args["sse"] = sse
   6154 
   6155 		// Put encrypted data
   6156 		_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(testCase.buf), int64(len(testCase.buf)), minio.PutObjectOptions{ServerSideEncryption: sse})
   6157 		if err != nil {
   6158 			logError(testName, function, args, startTime, "", "PutEncryptedObject failed", err)
   6159 			return
   6160 		}
   6161 
   6162 		// Read the data back without any encryption headers
   6163 		r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   6164 		if err != nil {
   6165 			logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
   6166 			return
   6167 		}
   6168 		defer r.Close()
   6169 
   6170 		// Compare the sent object with the received one
   6171 		recvBuffer := bytes.NewBuffer([]byte{})
   6172 		if _, err = io.Copy(recvBuffer, r); err != nil {
   6173 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
   6174 			return
   6175 		}
   6176 		if recvBuffer.Len() != len(testCase.buf) {
   6177 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
   6178 			return
   6179 		}
   6180 		if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
   6181 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
   6182 			return
   6183 		}
   6184 
   6185 		successLogger(testName, function, args, startTime).Info()
   6186 
   6187 	}
   6188 
   6189 	successLogger(testName, function, args, startTime).Info()
   6190 }
   6191 
   6192 // TestSSES3EncryptionFPut tests server side encryption
   6193 func testSSES3EncryptionFPut() {
   6194 	// initialize logging params
   6195 	startTime := time.Now()
   6196 	testName := getFuncName()
   6197 	function := "FPutEncryptedObject(bucketName, objectName, filePath, contentType, sse)"
   6198 	args := map[string]interface{}{
   6199 		"bucketName":  "",
   6200 		"objectName":  "",
   6201 		"filePath":    "",
   6202 		"contentType": "",
   6203 		"sse":         "",
   6204 	}
   6205 	// Seed random based on current time.
   6206 	rand.Seed(time.Now().Unix())
   6207 
   6208 	// Instantiate new minio client object
   6209 	c, err := minio.New(os.Getenv(serverEndpoint),
   6210 		&minio.Options{
   6211 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   6212 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   6213 		})
   6214 	if err != nil {
   6215 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   6216 		return
   6217 	}
   6218 
   6219 	// Enable tracing, write to stderr.
   6220 	// c.TraceOn(os.Stderr)
   6221 
   6222 	// Set user agent.
   6223 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   6224 
   6225 	// Generate a new random bucket name.
   6226 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   6227 	args["bucketName"] = bucketName
   6228 
   6229 	// Make a new bucket.
   6230 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   6231 	if err != nil {
   6232 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   6233 		return
   6234 	}
   6235 
   6236 	defer cleanupBucket(bucketName, c)
   6237 
   6238 	// Object custom metadata
   6239 	customContentType := "custom/contenttype"
   6240 	args["metadata"] = customContentType
   6241 
   6242 	testCases := []struct {
   6243 		buf []byte
   6244 	}{
   6245 		{buf: bytes.Repeat([]byte("F"), 0)},
   6246 		{buf: bytes.Repeat([]byte("F"), 1)},
   6247 		{buf: bytes.Repeat([]byte("F"), 15)},
   6248 		{buf: bytes.Repeat([]byte("F"), 16)},
   6249 		{buf: bytes.Repeat([]byte("F"), 17)},
   6250 		{buf: bytes.Repeat([]byte("F"), 31)},
   6251 		{buf: bytes.Repeat([]byte("F"), 32)},
   6252 		{buf: bytes.Repeat([]byte("F"), 33)},
   6253 		{buf: bytes.Repeat([]byte("F"), 1024)},
   6254 		{buf: bytes.Repeat([]byte("F"), 1024*2)},
   6255 		{buf: bytes.Repeat([]byte("F"), 1024*1024)},
   6256 	}
   6257 
   6258 	for i, testCase := range testCases {
   6259 		// Generate a random object name
   6260 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6261 		args["objectName"] = objectName
   6262 
   6263 		// Secured object
   6264 		sse := encrypt.NewSSE()
   6265 		args["sse"] = sse
   6266 
   6267 		// Generate a random file name.
   6268 		fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6269 		file, err := os.Create(fileName)
   6270 		if err != nil {
   6271 			logError(testName, function, args, startTime, "", "file create failed", err)
   6272 			return
   6273 		}
   6274 		_, err = file.Write(testCase.buf)
   6275 		if err != nil {
   6276 			logError(testName, function, args, startTime, "", "file write failed", err)
   6277 			return
   6278 		}
   6279 		file.Close()
   6280 		// Put encrypted data
   6281 		if _, err = c.FPutObject(context.Background(), bucketName, objectName, fileName, minio.PutObjectOptions{ServerSideEncryption: sse}); err != nil {
   6282 			logError(testName, function, args, startTime, "", "FPutEncryptedObject failed", err)
   6283 			return
   6284 		}
   6285 
   6286 		// Read the data back
   6287 		r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   6288 		if err != nil {
   6289 			logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
   6290 			return
   6291 		}
   6292 		defer r.Close()
   6293 
   6294 		// Compare the sent object with the received one
   6295 		recvBuffer := bytes.NewBuffer([]byte{})
   6296 		if _, err = io.Copy(recvBuffer, r); err != nil {
   6297 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
   6298 			return
   6299 		}
   6300 		if recvBuffer.Len() != len(testCase.buf) {
   6301 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
   6302 			return
   6303 		}
   6304 		if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
   6305 			logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
   6306 			return
   6307 		}
   6308 
   6309 		os.Remove(fileName)
   6310 	}
   6311 
   6312 	successLogger(testName, function, args, startTime).Info()
   6313 }
   6314 
   6315 func testBucketNotification() {
   6316 	// initialize logging params
   6317 	startTime := time.Now()
   6318 	testName := getFuncName()
   6319 	function := "SetBucketNotification(bucketName)"
   6320 	args := map[string]interface{}{
   6321 		"bucketName": "",
   6322 	}
   6323 
   6324 	if os.Getenv("NOTIFY_BUCKET") == "" ||
   6325 		os.Getenv("NOTIFY_SERVICE") == "" ||
   6326 		os.Getenv("NOTIFY_REGION") == "" ||
   6327 		os.Getenv("NOTIFY_ACCOUNTID") == "" ||
   6328 		os.Getenv("NOTIFY_RESOURCE") == "" {
   6329 		ignoredLog(testName, function, args, startTime, "Skipped notification test as it is not configured").Info()
   6330 		return
   6331 	}
   6332 
   6333 	// Seed random based on current time.
   6334 	rand.Seed(time.Now().Unix())
   6335 
   6336 	c, err := minio.New(os.Getenv(serverEndpoint),
   6337 		&minio.Options{
   6338 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   6339 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   6340 		})
   6341 	if err != nil {
   6342 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   6343 		return
   6344 	}
   6345 
   6346 	// Enable to debug
   6347 	// c.TraceOn(os.Stderr)
   6348 
   6349 	// Set user agent.
   6350 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   6351 
   6352 	bucketName := os.Getenv("NOTIFY_BUCKET")
   6353 	args["bucketName"] = bucketName
   6354 
   6355 	topicArn := notification.NewArn("aws", os.Getenv("NOTIFY_SERVICE"), os.Getenv("NOTIFY_REGION"), os.Getenv("NOTIFY_ACCOUNTID"), os.Getenv("NOTIFY_RESOURCE"))
   6356 	queueArn := notification.NewArn("aws", "dummy-service", "dummy-region", "dummy-accountid", "dummy-resource")
   6357 
   6358 	topicConfig := notification.NewConfig(topicArn)
   6359 	topicConfig.AddEvents(notification.ObjectCreatedAll, notification.ObjectRemovedAll)
   6360 	topicConfig.AddFilterSuffix("jpg")
   6361 
   6362 	queueConfig := notification.NewConfig(queueArn)
   6363 	queueConfig.AddEvents(notification.ObjectCreatedAll)
   6364 	queueConfig.AddFilterPrefix("photos/")
   6365 
   6366 	config := notification.Configuration{}
   6367 	config.AddTopic(topicConfig)
   6368 
   6369 	// Add the same topicConfig again, should have no effect
   6370 	// because it is duplicated
   6371 	config.AddTopic(topicConfig)
   6372 	if len(config.TopicConfigs) != 1 {
   6373 		logError(testName, function, args, startTime, "", "Duplicate entry added", err)
   6374 		return
   6375 	}
   6376 
   6377 	// Add and remove a queue config
   6378 	config.AddQueue(queueConfig)
   6379 	config.RemoveQueueByArn(queueArn)
   6380 
   6381 	err = c.SetBucketNotification(context.Background(), bucketName, config)
   6382 	if err != nil {
   6383 		logError(testName, function, args, startTime, "", "SetBucketNotification failed", err)
   6384 		return
   6385 	}
   6386 
   6387 	config, err = c.GetBucketNotification(context.Background(), bucketName)
   6388 	if err != nil {
   6389 		logError(testName, function, args, startTime, "", "GetBucketNotification failed", err)
   6390 		return
   6391 	}
   6392 
   6393 	if len(config.TopicConfigs) != 1 {
   6394 		logError(testName, function, args, startTime, "", "Topic config is empty", err)
   6395 		return
   6396 	}
   6397 
   6398 	if config.TopicConfigs[0].Filter.S3Key.FilterRules[0].Value != "jpg" {
   6399 		logError(testName, function, args, startTime, "", "Couldn't get the suffix", err)
   6400 		return
   6401 	}
   6402 
   6403 	err = c.RemoveAllBucketNotification(context.Background(), bucketName)
   6404 	if err != nil {
   6405 		logError(testName, function, args, startTime, "", "RemoveAllBucketNotification failed", err)
   6406 		return
   6407 	}
   6408 
   6409 	// Delete all objects and buckets
   6410 	if err = cleanupBucket(bucketName, c); err != nil {
   6411 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
   6412 		return
   6413 	}
   6414 
   6415 	successLogger(testName, function, args, startTime).Info()
   6416 }
   6417 
   6418 // Tests comprehensive list of all methods.
   6419 func testFunctional() {
   6420 	// initialize logging params
   6421 	startTime := time.Now()
   6422 	testName := getFuncName()
   6423 	function := "testFunctional()"
   6424 	functionAll := ""
   6425 	args := map[string]interface{}{}
   6426 
   6427 	// Seed random based on current time.
   6428 	rand.Seed(time.Now().Unix())
   6429 
   6430 	c, err := minio.New(os.Getenv(serverEndpoint),
   6431 		&minio.Options{
   6432 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   6433 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   6434 		})
   6435 	if err != nil {
   6436 		logError(testName, function, nil, startTime, "", "MinIO client object creation failed", err)
   6437 		return
   6438 	}
   6439 
   6440 	// Enable to debug
   6441 	// c.TraceOn(os.Stderr)
   6442 
   6443 	// Set user agent.
   6444 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   6445 
   6446 	// Generate a new random bucket name.
   6447 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   6448 
   6449 	// Make a new bucket.
   6450 	function = "MakeBucket(bucketName, region)"
   6451 	functionAll = "MakeBucket(bucketName, region)"
   6452 	args["bucketName"] = bucketName
   6453 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   6454 
   6455 	defer cleanupBucket(bucketName, c)
   6456 	if err != nil {
   6457 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   6458 		return
   6459 	}
   6460 
   6461 	// Generate a random file name.
   6462 	fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   6463 	file, err := os.Create(fileName)
   6464 	if err != nil {
   6465 		logError(testName, function, args, startTime, "", "File creation failed", err)
   6466 		return
   6467 	}
   6468 	for i := 0; i < 3; i++ {
   6469 		buf := make([]byte, rand.Intn(1<<19))
   6470 		_, err = file.Write(buf)
   6471 		if err != nil {
   6472 			logError(testName, function, args, startTime, "", "File write failed", err)
   6473 			return
   6474 		}
   6475 	}
   6476 	file.Close()
   6477 
   6478 	// Verify if bucket exits and you have access.
   6479 	var exists bool
   6480 	function = "BucketExists(bucketName)"
   6481 	functionAll += ", " + function
   6482 	args = map[string]interface{}{
   6483 		"bucketName": bucketName,
   6484 	}
   6485 	exists, err = c.BucketExists(context.Background(), bucketName)
   6486 
   6487 	if err != nil {
   6488 		logError(testName, function, args, startTime, "", "BucketExists failed", err)
   6489 		return
   6490 	}
   6491 	if !exists {
   6492 		logError(testName, function, args, startTime, "", "Could not find the bucket", err)
   6493 		return
   6494 	}
   6495 
   6496 	// Asserting the default bucket policy.
   6497 	function = "GetBucketPolicy(ctx, bucketName)"
   6498 	functionAll += ", " + function
   6499 	args = map[string]interface{}{
   6500 		"bucketName": bucketName,
   6501 	}
   6502 	nilPolicy, err := c.GetBucketPolicy(context.Background(), bucketName)
   6503 	if err != nil {
   6504 		logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
   6505 		return
   6506 	}
   6507 	if nilPolicy != "" {
   6508 		logError(testName, function, args, startTime, "", "policy should be set to nil", err)
   6509 		return
   6510 	}
   6511 
   6512 	// Set the bucket policy to 'public readonly'.
   6513 	function = "SetBucketPolicy(bucketName, readOnlyPolicy)"
   6514 	functionAll += ", " + function
   6515 
   6516 	readOnlyPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:ListBucket"],"Resource":["arn:aws:s3:::` + bucketName + `"]}]}`
   6517 	args = map[string]interface{}{
   6518 		"bucketName":   bucketName,
   6519 		"bucketPolicy": readOnlyPolicy,
   6520 	}
   6521 
   6522 	err = c.SetBucketPolicy(context.Background(), bucketName, readOnlyPolicy)
   6523 	if err != nil {
   6524 		logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
   6525 		return
   6526 	}
   6527 	// should return policy `readonly`.
   6528 	function = "GetBucketPolicy(ctx, bucketName)"
   6529 	functionAll += ", " + function
   6530 	args = map[string]interface{}{
   6531 		"bucketName": bucketName,
   6532 	}
   6533 	_, err = c.GetBucketPolicy(context.Background(), bucketName)
   6534 	if err != nil {
   6535 		logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
   6536 		return
   6537 	}
   6538 
   6539 	// Make the bucket 'public writeonly'.
   6540 	function = "SetBucketPolicy(bucketName, writeOnlyPolicy)"
   6541 	functionAll += ", " + function
   6542 
   6543 	writeOnlyPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:ListBucketMultipartUploads"],"Resource":["arn:aws:s3:::` + bucketName + `"]}]}`
   6544 	args = map[string]interface{}{
   6545 		"bucketName":   bucketName,
   6546 		"bucketPolicy": writeOnlyPolicy,
   6547 	}
   6548 	err = c.SetBucketPolicy(context.Background(), bucketName, writeOnlyPolicy)
   6549 
   6550 	if err != nil {
   6551 		logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
   6552 		return
   6553 	}
   6554 	// should return policy `writeonly`.
   6555 	function = "GetBucketPolicy(ctx, bucketName)"
   6556 	functionAll += ", " + function
   6557 	args = map[string]interface{}{
   6558 		"bucketName": bucketName,
   6559 	}
   6560 
   6561 	_, err = c.GetBucketPolicy(context.Background(), bucketName)
   6562 	if err != nil {
   6563 		logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
   6564 		return
   6565 	}
   6566 
   6567 	// Make the bucket 'public read/write'.
   6568 	function = "SetBucketPolicy(bucketName, readWritePolicy)"
   6569 	functionAll += ", " + function
   6570 
   6571 	readWritePolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:ListBucket","s3:ListBucketMultipartUploads"],"Resource":["arn:aws:s3:::` + bucketName + `"]}]}`
   6572 
   6573 	args = map[string]interface{}{
   6574 		"bucketName":   bucketName,
   6575 		"bucketPolicy": readWritePolicy,
   6576 	}
   6577 	err = c.SetBucketPolicy(context.Background(), bucketName, readWritePolicy)
   6578 
   6579 	if err != nil {
   6580 		logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
   6581 		return
   6582 	}
   6583 	// should return policy `readwrite`.
   6584 	function = "GetBucketPolicy(bucketName)"
   6585 	functionAll += ", " + function
   6586 	args = map[string]interface{}{
   6587 		"bucketName": bucketName,
   6588 	}
   6589 	_, err = c.GetBucketPolicy(context.Background(), bucketName)
   6590 	if err != nil {
   6591 		logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
   6592 		return
   6593 	}
   6594 
   6595 	// List all buckets.
   6596 	function = "ListBuckets()"
   6597 	functionAll += ", " + function
   6598 	args = nil
   6599 	buckets, err := c.ListBuckets(context.Background())
   6600 
   6601 	if len(buckets) == 0 {
   6602 		logError(testName, function, args, startTime, "", "Found bucket list to be empty", err)
   6603 		return
   6604 	}
   6605 	if err != nil {
   6606 		logError(testName, function, args, startTime, "", "ListBuckets failed", err)
   6607 		return
   6608 	}
   6609 
   6610 	// Verify if previously created bucket is listed in list buckets.
   6611 	bucketFound := false
   6612 	for _, bucket := range buckets {
   6613 		if bucket.Name == bucketName {
   6614 			bucketFound = true
   6615 		}
   6616 	}
   6617 
   6618 	// If bucket not found error out.
   6619 	if !bucketFound {
   6620 		logError(testName, function, args, startTime, "", "Bucket: "+bucketName+" not found", err)
   6621 		return
   6622 	}
   6623 
   6624 	objectName := bucketName + "unique"
   6625 
   6626 	// Generate data
   6627 	buf := bytes.Repeat([]byte("f"), 1<<19)
   6628 
   6629 	function = "PutObject(bucketName, objectName, reader, contentType)"
   6630 	functionAll += ", " + function
   6631 	args = map[string]interface{}{
   6632 		"bucketName":  bucketName,
   6633 		"objectName":  objectName,
   6634 		"contentType": "",
   6635 	}
   6636 
   6637 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
   6638 	if err != nil {
   6639 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   6640 		return
   6641 	}
   6642 
   6643 	args = map[string]interface{}{
   6644 		"bucketName":  bucketName,
   6645 		"objectName":  objectName + "-nolength",
   6646 		"contentType": "binary/octet-stream",
   6647 	}
   6648 
   6649 	_, err = c.PutObject(context.Background(), bucketName, objectName+"-nolength", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   6650 	if err != nil {
   6651 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   6652 		return
   6653 	}
   6654 
   6655 	// Instantiate a done channel to close all listing.
   6656 	doneCh := make(chan struct{})
   6657 	defer close(doneCh)
   6658 
   6659 	objFound := false
   6660 	isRecursive := true // Recursive is true.
   6661 
   6662 	function = "ListObjects(bucketName, objectName, isRecursive, doneCh)"
   6663 	functionAll += ", " + function
   6664 	args = map[string]interface{}{
   6665 		"bucketName":  bucketName,
   6666 		"objectName":  objectName,
   6667 		"isRecursive": isRecursive,
   6668 	}
   6669 
   6670 	for obj := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{UseV1: true, Prefix: objectName, Recursive: true}) {
   6671 		if obj.Key == objectName {
   6672 			objFound = true
   6673 			break
   6674 		}
   6675 	}
   6676 	if !objFound {
   6677 		logError(testName, function, args, startTime, "", "Object "+objectName+" not found", err)
   6678 		return
   6679 	}
   6680 
   6681 	objFound = false
   6682 	isRecursive = true // Recursive is true.
   6683 	function = "ListObjects()"
   6684 	functionAll += ", " + function
   6685 	args = map[string]interface{}{
   6686 		"bucketName":  bucketName,
   6687 		"objectName":  objectName,
   6688 		"isRecursive": isRecursive,
   6689 	}
   6690 
   6691 	for obj := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{Prefix: objectName, Recursive: isRecursive}) {
   6692 		if obj.Key == objectName {
   6693 			objFound = true
   6694 			break
   6695 		}
   6696 	}
   6697 	if !objFound {
   6698 		logError(testName, function, args, startTime, "", "Object "+objectName+" not found", err)
   6699 		return
   6700 	}
   6701 
   6702 	incompObjNotFound := true
   6703 
   6704 	function = "ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)"
   6705 	functionAll += ", " + function
   6706 	args = map[string]interface{}{
   6707 		"bucketName":  bucketName,
   6708 		"objectName":  objectName,
   6709 		"isRecursive": isRecursive,
   6710 	}
   6711 
   6712 	for objIncompl := range c.ListIncompleteUploads(context.Background(), bucketName, objectName, isRecursive) {
   6713 		if objIncompl.Key != "" {
   6714 			incompObjNotFound = false
   6715 			break
   6716 		}
   6717 	}
   6718 	if !incompObjNotFound {
   6719 		logError(testName, function, args, startTime, "", "Unexpected dangling incomplete upload found", err)
   6720 		return
   6721 	}
   6722 
   6723 	function = "GetObject(bucketName, objectName)"
   6724 	functionAll += ", " + function
   6725 	args = map[string]interface{}{
   6726 		"bucketName": bucketName,
   6727 		"objectName": objectName,
   6728 	}
   6729 	newReader, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   6730 	if err != nil {
   6731 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   6732 		return
   6733 	}
   6734 
   6735 	newReadBytes, err := io.ReadAll(newReader)
   6736 	if err != nil {
   6737 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   6738 		return
   6739 	}
   6740 
   6741 	if !bytes.Equal(newReadBytes, buf) {
   6742 		logError(testName, function, args, startTime, "", "GetObject bytes mismatch", err)
   6743 		return
   6744 	}
   6745 	newReader.Close()
   6746 
   6747 	function = "FGetObject(bucketName, objectName, fileName)"
   6748 	functionAll += ", " + function
   6749 	args = map[string]interface{}{
   6750 		"bucketName": bucketName,
   6751 		"objectName": objectName,
   6752 		"fileName":   fileName + "-f",
   6753 	}
   6754 	err = c.FGetObject(context.Background(), bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
   6755 
   6756 	if err != nil {
   6757 		logError(testName, function, args, startTime, "", "FGetObject failed", err)
   6758 		return
   6759 	}
   6760 
   6761 	function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
   6762 	functionAll += ", " + function
   6763 	args = map[string]interface{}{
   6764 		"bucketName": bucketName,
   6765 		"objectName": "",
   6766 		"expires":    3600 * time.Second,
   6767 	}
   6768 	if _, err = c.PresignedHeadObject(context.Background(), bucketName, "", 3600*time.Second, nil); err == nil {
   6769 		logError(testName, function, args, startTime, "", "PresignedHeadObject success", err)
   6770 		return
   6771 	}
   6772 
   6773 	// Generate presigned HEAD object url.
   6774 	function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
   6775 	functionAll += ", " + function
   6776 	args = map[string]interface{}{
   6777 		"bucketName": bucketName,
   6778 		"objectName": objectName,
   6779 		"expires":    3600 * time.Second,
   6780 	}
   6781 	presignedHeadURL, err := c.PresignedHeadObject(context.Background(), bucketName, objectName, 3600*time.Second, nil)
   6782 	if err != nil {
   6783 		logError(testName, function, args, startTime, "", "PresignedHeadObject failed", err)
   6784 		return
   6785 	}
   6786 
   6787 	transport, err := minio.DefaultTransport(mustParseBool(os.Getenv(enableHTTPS)))
   6788 	if err != nil {
   6789 		logError(testName, function, args, startTime, "", "DefaultTransport failed", err)
   6790 		return
   6791 	}
   6792 
   6793 	httpClient := &http.Client{
   6794 		// Setting a sensible time out of 30secs to wait for response
   6795 		// headers. Request is pro-actively canceled after 30secs
   6796 		// with no response.
   6797 		Timeout:   30 * time.Second,
   6798 		Transport: transport,
   6799 	}
   6800 
   6801 	req, err := http.NewRequest(http.MethodHead, presignedHeadURL.String(), nil)
   6802 	if err != nil {
   6803 		logError(testName, function, args, startTime, "", "PresignedHeadObject request was incorrect", err)
   6804 		return
   6805 	}
   6806 
   6807 	// Verify if presigned url works.
   6808 	resp, err := httpClient.Do(req)
   6809 	if err != nil {
   6810 		logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect", err)
   6811 		return
   6812 	}
   6813 	if resp.StatusCode != http.StatusOK {
   6814 		logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect, status "+string(resp.StatusCode), err)
   6815 		return
   6816 	}
   6817 	if resp.Header.Get("ETag") == "" {
   6818 		logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect", err)
   6819 		return
   6820 	}
   6821 	resp.Body.Close()
   6822 
   6823 	function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
   6824 	functionAll += ", " + function
   6825 	args = map[string]interface{}{
   6826 		"bucketName": bucketName,
   6827 		"objectName": "",
   6828 		"expires":    3600 * time.Second,
   6829 	}
   6830 	_, err = c.PresignedGetObject(context.Background(), bucketName, "", 3600*time.Second, nil)
   6831 	if err == nil {
   6832 		logError(testName, function, args, startTime, "", "PresignedGetObject success", err)
   6833 		return
   6834 	}
   6835 
   6836 	// Generate presigned GET object url.
   6837 	function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
   6838 	functionAll += ", " + function
   6839 	args = map[string]interface{}{
   6840 		"bucketName": bucketName,
   6841 		"objectName": objectName,
   6842 		"expires":    3600 * time.Second,
   6843 	}
   6844 	presignedGetURL, err := c.PresignedGetObject(context.Background(), bucketName, objectName, 3600*time.Second, nil)
   6845 	if err != nil {
   6846 		logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
   6847 		return
   6848 	}
   6849 
   6850 	// Verify if presigned url works.
   6851 	req, err = http.NewRequest(http.MethodGet, presignedGetURL.String(), nil)
   6852 	if err != nil {
   6853 		logError(testName, function, args, startTime, "", "PresignedGetObject request incorrect", err)
   6854 		return
   6855 	}
   6856 
   6857 	resp, err = httpClient.Do(req)
   6858 	if err != nil {
   6859 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
   6860 		return
   6861 	}
   6862 	if resp.StatusCode != http.StatusOK {
   6863 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect, status "+string(resp.StatusCode), err)
   6864 		return
   6865 	}
   6866 	newPresignedBytes, err := io.ReadAll(resp.Body)
   6867 	if err != nil {
   6868 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
   6869 		return
   6870 	}
   6871 	resp.Body.Close()
   6872 	if !bytes.Equal(newPresignedBytes, buf) {
   6873 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
   6874 		return
   6875 	}
   6876 
   6877 	// Set request parameters.
   6878 	reqParams := make(url.Values)
   6879 	reqParams.Set("response-content-disposition", "attachment; filename=\"test.txt\"")
   6880 	args = map[string]interface{}{
   6881 		"bucketName": bucketName,
   6882 		"objectName": objectName,
   6883 		"expires":    3600 * time.Second,
   6884 		"reqParams":  reqParams,
   6885 	}
   6886 	presignedGetURL, err = c.PresignedGetObject(context.Background(), bucketName, objectName, 3600*time.Second, reqParams)
   6887 
   6888 	if err != nil {
   6889 		logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
   6890 		return
   6891 	}
   6892 
   6893 	// Verify if presigned url works.
   6894 	req, err = http.NewRequest(http.MethodGet, presignedGetURL.String(), nil)
   6895 	if err != nil {
   6896 		logError(testName, function, args, startTime, "", "PresignedGetObject request incorrect", err)
   6897 		return
   6898 	}
   6899 
   6900 	resp, err = httpClient.Do(req)
   6901 	if err != nil {
   6902 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
   6903 		return
   6904 	}
   6905 	if resp.StatusCode != http.StatusOK {
   6906 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect, status "+string(resp.StatusCode), err)
   6907 		return
   6908 	}
   6909 	newPresignedBytes, err = io.ReadAll(resp.Body)
   6910 	if err != nil {
   6911 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
   6912 		return
   6913 	}
   6914 	if !bytes.Equal(newPresignedBytes, buf) {
   6915 		logError(testName, function, args, startTime, "", "Bytes mismatch for presigned GET URL", err)
   6916 		return
   6917 	}
   6918 	if resp.Header.Get("Content-Disposition") != "attachment; filename=\"test.txt\"" {
   6919 		logError(testName, function, args, startTime, "", "wrong Content-Disposition received "+string(resp.Header.Get("Content-Disposition")), err)
   6920 		return
   6921 	}
   6922 
   6923 	function = "PresignedPutObject(bucketName, objectName, expires)"
   6924 	functionAll += ", " + function
   6925 	args = map[string]interface{}{
   6926 		"bucketName": bucketName,
   6927 		"objectName": "",
   6928 		"expires":    3600 * time.Second,
   6929 	}
   6930 	_, err = c.PresignedPutObject(context.Background(), bucketName, "", 3600*time.Second)
   6931 	if err == nil {
   6932 		logError(testName, function, args, startTime, "", "PresignedPutObject success", err)
   6933 		return
   6934 	}
   6935 
   6936 	function = "PresignedPutObject(bucketName, objectName, expires)"
   6937 	functionAll += ", " + function
   6938 	args = map[string]interface{}{
   6939 		"bucketName": bucketName,
   6940 		"objectName": objectName + "-presigned",
   6941 		"expires":    3600 * time.Second,
   6942 	}
   6943 	presignedPutURL, err := c.PresignedPutObject(context.Background(), bucketName, objectName+"-presigned", 3600*time.Second)
   6944 	if err != nil {
   6945 		logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
   6946 		return
   6947 	}
   6948 
   6949 	buf = bytes.Repeat([]byte("g"), 1<<19)
   6950 
   6951 	req, err = http.NewRequest(http.MethodPut, presignedPutURL.String(), bytes.NewReader(buf))
   6952 	if err != nil {
   6953 		logError(testName, function, args, startTime, "", "Couldn't make HTTP request with PresignedPutObject URL", err)
   6954 		return
   6955 	}
   6956 
   6957 	resp, err = httpClient.Do(req)
   6958 	if err != nil {
   6959 		logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
   6960 		return
   6961 	}
   6962 
   6963 	newReader, err = c.GetObject(context.Background(), bucketName, objectName+"-presigned", minio.GetObjectOptions{})
   6964 	if err != nil {
   6965 		logError(testName, function, args, startTime, "", "GetObject after PresignedPutObject failed", err)
   6966 		return
   6967 	}
   6968 
   6969 	newReadBytes, err = io.ReadAll(newReader)
   6970 	if err != nil {
   6971 		logError(testName, function, args, startTime, "", "ReadAll after GetObject failed", err)
   6972 		return
   6973 	}
   6974 
   6975 	if !bytes.Equal(newReadBytes, buf) {
   6976 		logError(testName, function, args, startTime, "", "Bytes mismatch", err)
   6977 		return
   6978 	}
   6979 
   6980 	function = "PresignHeader(method, bucketName, objectName, expires, reqParams, extraHeaders)"
   6981 	functionAll += ", " + function
   6982 	presignExtraHeaders := map[string][]string{
   6983 		"mysecret": {"abcxxx"},
   6984 	}
   6985 	args = map[string]interface{}{
   6986 		"method":       "PUT",
   6987 		"bucketName":   bucketName,
   6988 		"objectName":   objectName + "-presign-custom",
   6989 		"expires":      3600 * time.Second,
   6990 		"extraHeaders": presignExtraHeaders,
   6991 	}
   6992 	presignedURL, err := c.PresignHeader(context.Background(), "PUT", bucketName, objectName+"-presign-custom", 3600*time.Second, nil, presignExtraHeaders)
   6993 	if err != nil {
   6994 		logError(testName, function, args, startTime, "", "Presigned failed", err)
   6995 		return
   6996 	}
   6997 
   6998 	// Generate data more than 32K
   6999 	buf = bytes.Repeat([]byte("1"), rand.Intn(1<<10)+32*1024)
   7000 
   7001 	req, err = http.NewRequest(http.MethodPut, presignedURL.String(), bytes.NewReader(buf))
   7002 	if err != nil {
   7003 		logError(testName, function, args, startTime, "", "HTTP request to Presigned URL failed", err)
   7004 		return
   7005 	}
   7006 
   7007 	req.Header.Add("mysecret", "abcxxx")
   7008 	resp, err = httpClient.Do(req)
   7009 	if err != nil {
   7010 		logError(testName, function, args, startTime, "", "HTTP request to Presigned URL failed", err)
   7011 		return
   7012 	}
   7013 
   7014 	// Download the uploaded object to verify
   7015 	args = map[string]interface{}{
   7016 		"bucketName": bucketName,
   7017 		"objectName": objectName + "-presign-custom",
   7018 	}
   7019 	newReader, err = c.GetObject(context.Background(), bucketName, objectName+"-presign-custom", minio.GetObjectOptions{})
   7020 	if err != nil {
   7021 		logError(testName, function, args, startTime, "", "GetObject of uploaded custom-presigned object failed", err)
   7022 		return
   7023 	}
   7024 
   7025 	newReadBytes, err = io.ReadAll(newReader)
   7026 	if err != nil {
   7027 		logError(testName, function, args, startTime, "", "ReadAll failed during get on custom-presigned put object", err)
   7028 		return
   7029 	}
   7030 	newReader.Close()
   7031 
   7032 	if !bytes.Equal(newReadBytes, buf) {
   7033 		logError(testName, function, args, startTime, "", "Bytes mismatch on custom-presigned object upload verification", err)
   7034 		return
   7035 	}
   7036 
   7037 	function = "RemoveObject(bucketName, objectName)"
   7038 	functionAll += ", " + function
   7039 	args = map[string]interface{}{
   7040 		"bucketName": bucketName,
   7041 		"objectName": objectName,
   7042 	}
   7043 	err = c.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
   7044 
   7045 	if err != nil {
   7046 		logError(testName, function, args, startTime, "", "RemoveObject failed", err)
   7047 		return
   7048 	}
   7049 	args["objectName"] = objectName + "-f"
   7050 	err = c.RemoveObject(context.Background(), bucketName, objectName+"-f", minio.RemoveObjectOptions{})
   7051 
   7052 	if err != nil {
   7053 		logError(testName, function, args, startTime, "", "RemoveObject failed", err)
   7054 		return
   7055 	}
   7056 
   7057 	args["objectName"] = objectName + "-nolength"
   7058 	err = c.RemoveObject(context.Background(), bucketName, objectName+"-nolength", minio.RemoveObjectOptions{})
   7059 
   7060 	if err != nil {
   7061 		logError(testName, function, args, startTime, "", "RemoveObject failed", err)
   7062 		return
   7063 	}
   7064 
   7065 	args["objectName"] = objectName + "-presigned"
   7066 	err = c.RemoveObject(context.Background(), bucketName, objectName+"-presigned", minio.RemoveObjectOptions{})
   7067 
   7068 	if err != nil {
   7069 		logError(testName, function, args, startTime, "", "RemoveObject failed", err)
   7070 		return
   7071 	}
   7072 
   7073 	args["objectName"] = objectName + "-presign-custom"
   7074 	err = c.RemoveObject(context.Background(), bucketName, objectName+"-presign-custom", minio.RemoveObjectOptions{})
   7075 
   7076 	if err != nil {
   7077 		logError(testName, function, args, startTime, "", "RemoveObject failed", err)
   7078 		return
   7079 	}
   7080 
   7081 	function = "RemoveBucket(bucketName)"
   7082 	functionAll += ", " + function
   7083 	args = map[string]interface{}{
   7084 		"bucketName": bucketName,
   7085 	}
   7086 	err = c.RemoveBucket(context.Background(), bucketName)
   7087 
   7088 	if err != nil {
   7089 		logError(testName, function, args, startTime, "", "RemoveBucket failed", err)
   7090 		return
   7091 	}
   7092 	err = c.RemoveBucket(context.Background(), bucketName)
   7093 	if err == nil {
   7094 		logError(testName, function, args, startTime, "", "RemoveBucket did not fail for invalid bucket name", err)
   7095 		return
   7096 	}
   7097 	if err.Error() != "The specified bucket does not exist" {
   7098 		logError(testName, function, args, startTime, "", "RemoveBucket failed", err)
   7099 		return
   7100 	}
   7101 
   7102 	os.Remove(fileName)
   7103 	os.Remove(fileName + "-f")
   7104 	successLogger(testName, functionAll, args, startTime).Info()
   7105 }
   7106 
   7107 // Test for validating GetObject Reader* methods functioning when the
   7108 // object is modified in the object store.
   7109 func testGetObjectModified() {
   7110 	// initialize logging params
   7111 	startTime := time.Now()
   7112 	testName := getFuncName()
   7113 	function := "GetObject(bucketName, objectName)"
   7114 	args := map[string]interface{}{}
   7115 
   7116 	// Instantiate new minio client object.
   7117 	c, err := minio.New(os.Getenv(serverEndpoint),
   7118 		&minio.Options{
   7119 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7120 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7121 		})
   7122 	if err != nil {
   7123 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   7124 		return
   7125 	}
   7126 
   7127 	// Enable tracing, write to stderr.
   7128 	// c.TraceOn(os.Stderr)
   7129 
   7130 	// Set user agent.
   7131 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7132 
   7133 	// Make a new bucket.
   7134 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7135 	args["bucketName"] = bucketName
   7136 
   7137 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7138 	if err != nil {
   7139 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7140 		return
   7141 	}
   7142 
   7143 	defer cleanupBucket(bucketName, c)
   7144 
   7145 	// Upload an object.
   7146 	objectName := "myobject"
   7147 	args["objectName"] = objectName
   7148 	content := "helloworld"
   7149 	_, err = c.PutObject(context.Background(), bucketName, objectName, strings.NewReader(content), int64(len(content)), minio.PutObjectOptions{ContentType: "application/text"})
   7150 	if err != nil {
   7151 		logError(testName, function, args, startTime, "", "Failed to upload "+objectName+", to bucket "+bucketName, err)
   7152 		return
   7153 	}
   7154 
   7155 	defer c.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
   7156 
   7157 	reader, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   7158 	if err != nil {
   7159 		logError(testName, function, args, startTime, "", "Failed to GetObject "+objectName+", from bucket "+bucketName, err)
   7160 		return
   7161 	}
   7162 	defer reader.Close()
   7163 
   7164 	// Read a few bytes of the object.
   7165 	b := make([]byte, 5)
   7166 	n, err := reader.ReadAt(b, 0)
   7167 	if err != nil {
   7168 		logError(testName, function, args, startTime, "", "Failed to read object "+objectName+", from bucket "+bucketName+" at an offset", err)
   7169 		return
   7170 	}
   7171 
   7172 	// Upload different contents to the same object while object is being read.
   7173 	newContent := "goodbyeworld"
   7174 	_, err = c.PutObject(context.Background(), bucketName, objectName, strings.NewReader(newContent), int64(len(newContent)), minio.PutObjectOptions{ContentType: "application/text"})
   7175 	if err != nil {
   7176 		logError(testName, function, args, startTime, "", "Failed to upload "+objectName+", to bucket "+bucketName, err)
   7177 		return
   7178 	}
   7179 
   7180 	// Confirm that a Stat() call in between doesn't change the Object's cached etag.
   7181 	_, err = reader.Stat()
   7182 	expectedError := "At least one of the pre-conditions you specified did not hold"
   7183 	if err.Error() != expectedError {
   7184 		logError(testName, function, args, startTime, "", "Expected Stat to fail with error "+expectedError+", but received "+err.Error(), err)
   7185 		return
   7186 	}
   7187 
   7188 	// Read again only to find object contents have been modified since last read.
   7189 	_, err = reader.ReadAt(b, int64(n))
   7190 	if err.Error() != expectedError {
   7191 		logError(testName, function, args, startTime, "", "Expected ReadAt to fail with error "+expectedError+", but received "+err.Error(), err)
   7192 		return
   7193 	}
   7194 
   7195 	successLogger(testName, function, args, startTime).Info()
   7196 }
   7197 
   7198 // Test validates putObject to upload a file seeked at a given offset.
   7199 func testPutObjectUploadSeekedObject() {
   7200 	// initialize logging params
   7201 	startTime := time.Now()
   7202 	testName := getFuncName()
   7203 	function := "PutObject(bucketName, objectName, fileToUpload, contentType)"
   7204 	args := map[string]interface{}{
   7205 		"bucketName":   "",
   7206 		"objectName":   "",
   7207 		"fileToUpload": "",
   7208 		"contentType":  "binary/octet-stream",
   7209 	}
   7210 
   7211 	// Instantiate new minio client object.
   7212 	c, err := minio.New(os.Getenv(serverEndpoint),
   7213 		&minio.Options{
   7214 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7215 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7216 		})
   7217 	if err != nil {
   7218 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
   7219 		return
   7220 	}
   7221 
   7222 	// Enable tracing, write to stderr.
   7223 	// c.TraceOn(os.Stderr)
   7224 
   7225 	// Set user agent.
   7226 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7227 
   7228 	// Make a new bucket.
   7229 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7230 	args["bucketName"] = bucketName
   7231 
   7232 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7233 	if err != nil {
   7234 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7235 		return
   7236 	}
   7237 	defer cleanupBucket(bucketName, c)
   7238 
   7239 	var tempfile *os.File
   7240 
   7241 	if fileName := getMintDataDirFilePath("datafile-100-kB"); fileName != "" {
   7242 		tempfile, err = os.Open(fileName)
   7243 		if err != nil {
   7244 			logError(testName, function, args, startTime, "", "File open failed", err)
   7245 			return
   7246 		}
   7247 		args["fileToUpload"] = fileName
   7248 	} else {
   7249 		tempfile, err = os.CreateTemp("", "minio-go-upload-test-")
   7250 		if err != nil {
   7251 			logError(testName, function, args, startTime, "", "TempFile create failed", err)
   7252 			return
   7253 		}
   7254 		args["fileToUpload"] = tempfile.Name()
   7255 
   7256 		// Generate 100kB data
   7257 		if _, err = io.Copy(tempfile, getDataReader("datafile-100-kB")); err != nil {
   7258 			logError(testName, function, args, startTime, "", "File copy failed", err)
   7259 			return
   7260 		}
   7261 
   7262 		defer os.Remove(tempfile.Name())
   7263 
   7264 		// Seek back to the beginning of the file.
   7265 		tempfile.Seek(0, 0)
   7266 	}
   7267 	length := 100 * humanize.KiByte
   7268 	objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
   7269 	args["objectName"] = objectName
   7270 
   7271 	offset := length / 2
   7272 	if _, err = tempfile.Seek(int64(offset), 0); err != nil {
   7273 		logError(testName, function, args, startTime, "", "TempFile seek failed", err)
   7274 		return
   7275 	}
   7276 
   7277 	_, err = c.PutObject(context.Background(), bucketName, objectName, tempfile, int64(length-offset), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   7278 	if err != nil {
   7279 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   7280 		return
   7281 	}
   7282 	tempfile.Close()
   7283 
   7284 	obj, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   7285 	if err != nil {
   7286 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   7287 		return
   7288 	}
   7289 	defer obj.Close()
   7290 
   7291 	n, err := obj.Seek(int64(offset), 0)
   7292 	if err != nil {
   7293 		logError(testName, function, args, startTime, "", "Seek failed", err)
   7294 		return
   7295 	}
   7296 	if n != int64(offset) {
   7297 		logError(testName, function, args, startTime, "", fmt.Sprintf("Invalid offset returned, expected %d got %d", int64(offset), n), err)
   7298 		return
   7299 	}
   7300 
   7301 	_, err = c.PutObject(context.Background(), bucketName, objectName+"getobject", obj, int64(length-offset), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   7302 	if err != nil {
   7303 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   7304 		return
   7305 	}
   7306 	st, err := c.StatObject(context.Background(), bucketName, objectName+"getobject", minio.StatObjectOptions{})
   7307 	if err != nil {
   7308 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   7309 		return
   7310 	}
   7311 	if st.Size != int64(length-offset) {
   7312 		logError(testName, function, args, startTime, "", fmt.Sprintf("Invalid offset returned, expected %d got %d", int64(length-offset), n), err)
   7313 		return
   7314 	}
   7315 
   7316 	successLogger(testName, function, args, startTime).Info()
   7317 }
   7318 
   7319 // Tests bucket re-create errors.
   7320 func testMakeBucketErrorV2() {
   7321 	// initialize logging params
   7322 	startTime := time.Now()
   7323 	testName := getFuncName()
   7324 	function := "MakeBucket(bucketName, region)"
   7325 	args := map[string]interface{}{
   7326 		"bucketName": "",
   7327 		"region":     "eu-west-1",
   7328 	}
   7329 
   7330 	// Seed random based on current time.
   7331 	rand.Seed(time.Now().Unix())
   7332 
   7333 	// Instantiate new minio client object.
   7334 	c, err := minio.New(os.Getenv(serverEndpoint),
   7335 		&minio.Options{
   7336 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7337 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7338 		})
   7339 	if err != nil {
   7340 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7341 		return
   7342 	}
   7343 
   7344 	// Enable tracing, write to stderr.
   7345 	// c.TraceOn(os.Stderr)
   7346 
   7347 	// Set user agent.
   7348 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7349 
   7350 	// Generate a new random bucket name.
   7351 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7352 	region := "eu-west-1"
   7353 	args["bucketName"] = bucketName
   7354 	args["region"] = region
   7355 
   7356 	// Make a new bucket in 'eu-west-1'.
   7357 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region}); err != nil {
   7358 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7359 		return
   7360 	}
   7361 
   7362 	defer cleanupBucket(bucketName, c)
   7363 
   7364 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: region}); err == nil {
   7365 		logError(testName, function, args, startTime, "", "MakeBucket did not fail for existing bucket name", err)
   7366 		return
   7367 	}
   7368 	// Verify valid error response from server.
   7369 	if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
   7370 		minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
   7371 		logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
   7372 		return
   7373 	}
   7374 
   7375 	successLogger(testName, function, args, startTime).Info()
   7376 }
   7377 
   7378 // Test get object reader to not throw error on being closed twice.
   7379 func testGetObjectClosedTwiceV2() {
   7380 	// initialize logging params
   7381 	startTime := time.Now()
   7382 	testName := getFuncName()
   7383 	function := "MakeBucket(bucketName, region)"
   7384 	args := map[string]interface{}{
   7385 		"bucketName": "",
   7386 		"region":     "eu-west-1",
   7387 	}
   7388 
   7389 	// Seed random based on current time.
   7390 	rand.Seed(time.Now().Unix())
   7391 
   7392 	// Instantiate new minio client object.
   7393 	c, err := minio.New(os.Getenv(serverEndpoint),
   7394 		&minio.Options{
   7395 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7396 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7397 		})
   7398 	if err != nil {
   7399 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7400 		return
   7401 	}
   7402 
   7403 	// Enable tracing, write to stderr.
   7404 	// c.TraceOn(os.Stderr)
   7405 
   7406 	// Set user agent.
   7407 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7408 
   7409 	// Generate a new random bucket name.
   7410 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7411 	args["bucketName"] = bucketName
   7412 
   7413 	// Make a new bucket.
   7414 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7415 	if err != nil {
   7416 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7417 		return
   7418 	}
   7419 
   7420 	defer cleanupBucket(bucketName, c)
   7421 
   7422 	// Generate 33K of data.
   7423 	bufSize := dataFileMap["datafile-33-kB"]
   7424 	reader := getDataReader("datafile-33-kB")
   7425 	defer reader.Close()
   7426 
   7427 	// Save the data
   7428 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   7429 	args["objectName"] = objectName
   7430 
   7431 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   7432 	if err != nil {
   7433 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   7434 		return
   7435 	}
   7436 
   7437 	// Read the data back
   7438 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   7439 	if err != nil {
   7440 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   7441 		return
   7442 	}
   7443 
   7444 	st, err := r.Stat()
   7445 	if err != nil {
   7446 		logError(testName, function, args, startTime, "", "Stat failed", err)
   7447 		return
   7448 	}
   7449 
   7450 	if st.Size != int64(bufSize) {
   7451 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
   7452 		return
   7453 	}
   7454 	if err := r.Close(); err != nil {
   7455 		logError(testName, function, args, startTime, "", "Stat failed", err)
   7456 		return
   7457 	}
   7458 	if err := r.Close(); err == nil {
   7459 		logError(testName, function, args, startTime, "", "Object is already closed, should return error", err)
   7460 		return
   7461 	}
   7462 
   7463 	successLogger(testName, function, args, startTime).Info()
   7464 }
   7465 
   7466 // Tests FPutObject hidden contentType setting
   7467 func testFPutObjectV2() {
   7468 	// initialize logging params
   7469 	startTime := time.Now()
   7470 	testName := getFuncName()
   7471 	function := "FPutObject(bucketName, objectName, fileName, opts)"
   7472 	args := map[string]interface{}{
   7473 		"bucketName": "",
   7474 		"objectName": "",
   7475 		"fileName":   "",
   7476 		"opts":       "",
   7477 	}
   7478 
   7479 	// Seed random based on current time.
   7480 	rand.Seed(time.Now().Unix())
   7481 
   7482 	// Instantiate new minio client object.
   7483 	c, err := minio.New(os.Getenv(serverEndpoint),
   7484 		&minio.Options{
   7485 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7486 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7487 		})
   7488 	if err != nil {
   7489 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7490 		return
   7491 	}
   7492 
   7493 	// Enable tracing, write to stderr.
   7494 	// c.TraceOn(os.Stderr)
   7495 
   7496 	// Set user agent.
   7497 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7498 
   7499 	// Generate a new random bucket name.
   7500 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7501 	args["bucketName"] = bucketName
   7502 
   7503 	// Make a new bucket.
   7504 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7505 	if err != nil {
   7506 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7507 		return
   7508 	}
   7509 
   7510 	defer cleanupBucket(bucketName, c)
   7511 
   7512 	// Make a temp file with 11*1024*1024 bytes of data.
   7513 	file, err := os.CreateTemp(os.TempDir(), "FPutObjectTest")
   7514 	if err != nil {
   7515 		logError(testName, function, args, startTime, "", "TempFile creation failed", err)
   7516 		return
   7517 	}
   7518 
   7519 	r := bytes.NewReader(bytes.Repeat([]byte("b"), 11*1024*1024))
   7520 	n, err := io.CopyN(file, r, 11*1024*1024)
   7521 	if err != nil {
   7522 		logError(testName, function, args, startTime, "", "Copy failed", err)
   7523 		return
   7524 	}
   7525 	if n != int64(11*1024*1024) {
   7526 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(11*1024*1024))+" got "+string(n), err)
   7527 		return
   7528 	}
   7529 
   7530 	// Close the file pro-actively for windows.
   7531 	err = file.Close()
   7532 	if err != nil {
   7533 		logError(testName, function, args, startTime, "", "File close failed", err)
   7534 		return
   7535 	}
   7536 
   7537 	// Set base object name
   7538 	objectName := bucketName + "FPutObject"
   7539 	args["objectName"] = objectName
   7540 	args["fileName"] = file.Name()
   7541 
   7542 	// Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
   7543 	_, err = c.FPutObject(context.Background(), bucketName, objectName+"-standard", file.Name(), minio.PutObjectOptions{ContentType: "application/octet-stream"})
   7544 	if err != nil {
   7545 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   7546 		return
   7547 	}
   7548 
   7549 	// Perform FPutObject with no contentType provided (Expecting application/octet-stream)
   7550 	args["objectName"] = objectName + "-Octet"
   7551 	args["contentType"] = ""
   7552 
   7553 	_, err = c.FPutObject(context.Background(), bucketName, objectName+"-Octet", file.Name(), minio.PutObjectOptions{})
   7554 	if err != nil {
   7555 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   7556 		return
   7557 	}
   7558 
   7559 	// Add extension to temp file name
   7560 	fileName := file.Name()
   7561 	err = os.Rename(fileName, fileName+".gtar")
   7562 	if err != nil {
   7563 		logError(testName, function, args, startTime, "", "Rename failed", err)
   7564 		return
   7565 	}
   7566 
   7567 	// Perform FPutObject with no contentType provided (Expecting application/x-gtar)
   7568 	args["objectName"] = objectName + "-Octet"
   7569 	args["contentType"] = ""
   7570 	args["fileName"] = fileName + ".gtar"
   7571 
   7572 	_, err = c.FPutObject(context.Background(), bucketName, objectName+"-GTar", fileName+".gtar", minio.PutObjectOptions{})
   7573 	if err != nil {
   7574 		logError(testName, function, args, startTime, "", "FPutObject failed", err)
   7575 		return
   7576 	}
   7577 
   7578 	// Check headers and sizes
   7579 	rStandard, err := c.StatObject(context.Background(), bucketName, objectName+"-standard", minio.StatObjectOptions{})
   7580 	if err != nil {
   7581 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   7582 		return
   7583 	}
   7584 
   7585 	if rStandard.Size != 11*1024*1024 {
   7586 		logError(testName, function, args, startTime, "", "Unexpected size", nil)
   7587 		return
   7588 	}
   7589 
   7590 	if rStandard.ContentType != "application/octet-stream" {
   7591 		logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/octet-stream , got "+rStandard.ContentType, err)
   7592 		return
   7593 	}
   7594 
   7595 	rOctet, err := c.StatObject(context.Background(), bucketName, objectName+"-Octet", minio.StatObjectOptions{})
   7596 	if err != nil {
   7597 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   7598 		return
   7599 	}
   7600 	if rOctet.ContentType != "application/octet-stream" {
   7601 		logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/octet-stream , got "+rOctet.ContentType, err)
   7602 		return
   7603 	}
   7604 
   7605 	if rOctet.Size != 11*1024*1024 {
   7606 		logError(testName, function, args, startTime, "", "Unexpected size", nil)
   7607 		return
   7608 	}
   7609 
   7610 	rGTar, err := c.StatObject(context.Background(), bucketName, objectName+"-GTar", minio.StatObjectOptions{})
   7611 	if err != nil {
   7612 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   7613 		return
   7614 	}
   7615 	if rGTar.Size != 11*1024*1024 {
   7616 		logError(testName, function, args, startTime, "", "Unexpected size", nil)
   7617 		return
   7618 	}
   7619 	if rGTar.ContentType != "application/x-gtar" && rGTar.ContentType != "application/octet-stream" && rGTar.ContentType != "application/x-tar" {
   7620 		logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/x-tar , got "+rGTar.ContentType, err)
   7621 		return
   7622 	}
   7623 
   7624 	os.Remove(fileName + ".gtar")
   7625 	successLogger(testName, function, args, startTime).Info()
   7626 }
   7627 
   7628 // Tests various bucket supported formats.
   7629 func testMakeBucketRegionsV2() {
   7630 	// initialize logging params
   7631 	startTime := time.Now()
   7632 	testName := getFuncName()
   7633 	function := "MakeBucket(bucketName, region)"
   7634 	args := map[string]interface{}{
   7635 		"bucketName": "",
   7636 		"region":     "eu-west-1",
   7637 	}
   7638 
   7639 	// Seed random based on current time.
   7640 	rand.Seed(time.Now().Unix())
   7641 
   7642 	// Instantiate new minio client object.
   7643 	c, err := minio.New(os.Getenv(serverEndpoint),
   7644 		&minio.Options{
   7645 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7646 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7647 		})
   7648 	if err != nil {
   7649 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7650 		return
   7651 	}
   7652 
   7653 	// Enable tracing, write to stderr.
   7654 	// c.TraceOn(os.Stderr)
   7655 
   7656 	// Set user agent.
   7657 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7658 
   7659 	// Generate a new random bucket name.
   7660 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7661 	args["bucketName"] = bucketName
   7662 
   7663 	// Make a new bucket in 'eu-central-1'.
   7664 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "eu-west-1"}); err != nil {
   7665 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7666 		return
   7667 	}
   7668 
   7669 	if err = cleanupBucket(bucketName, c); err != nil {
   7670 		logError(testName, function, args, startTime, "", "CleanupBucket failed while removing bucket recursively", err)
   7671 		return
   7672 	}
   7673 
   7674 	// Make a new bucket with '.' in its name, in 'us-west-2'. This
   7675 	// request is internally staged into a path style instead of
   7676 	// virtual host style.
   7677 	if err = c.MakeBucket(context.Background(), bucketName+".withperiod", minio.MakeBucketOptions{Region: "us-west-2"}); err != nil {
   7678 		args["bucketName"] = bucketName + ".withperiod"
   7679 		args["region"] = "us-west-2"
   7680 		logError(testName, function, args, startTime, "", "MakeBucket test with a bucket name with period, '.', failed", err)
   7681 		return
   7682 	}
   7683 
   7684 	// Delete all objects and buckets
   7685 	if err = cleanupBucket(bucketName+".withperiod", c); err != nil {
   7686 		logError(testName, function, args, startTime, "", "CleanupBucket failed while removing bucket recursively", err)
   7687 		return
   7688 	}
   7689 
   7690 	successLogger(testName, function, args, startTime).Info()
   7691 }
   7692 
   7693 // Tests get object ReaderSeeker interface methods.
   7694 func testGetObjectReadSeekFunctionalV2() {
   7695 	// initialize logging params
   7696 	startTime := time.Now()
   7697 	testName := getFuncName()
   7698 	function := "GetObject(bucketName, objectName)"
   7699 	args := map[string]interface{}{}
   7700 
   7701 	// Seed random based on current time.
   7702 	rand.Seed(time.Now().Unix())
   7703 
   7704 	// Instantiate new minio client object.
   7705 	c, err := minio.New(os.Getenv(serverEndpoint),
   7706 		&minio.Options{
   7707 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7708 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7709 		})
   7710 	if err != nil {
   7711 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7712 		return
   7713 	}
   7714 
   7715 	// Enable tracing, write to stderr.
   7716 	// c.TraceOn(os.Stderr)
   7717 
   7718 	// Set user agent.
   7719 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7720 
   7721 	// Generate a new random bucket name.
   7722 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7723 	args["bucketName"] = bucketName
   7724 
   7725 	// Make a new bucket.
   7726 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7727 	if err != nil {
   7728 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7729 		return
   7730 	}
   7731 
   7732 	defer cleanupBucket(bucketName, c)
   7733 
   7734 	// Generate 33K of data.
   7735 	bufSize := dataFileMap["datafile-33-kB"]
   7736 	reader := getDataReader("datafile-33-kB")
   7737 	defer reader.Close()
   7738 
   7739 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   7740 	args["objectName"] = objectName
   7741 
   7742 	buf, err := io.ReadAll(reader)
   7743 	if err != nil {
   7744 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   7745 		return
   7746 	}
   7747 
   7748 	// Save the data.
   7749 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   7750 	if err != nil {
   7751 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   7752 		return
   7753 	}
   7754 
   7755 	// Read the data back
   7756 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   7757 	if err != nil {
   7758 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   7759 		return
   7760 	}
   7761 	defer r.Close()
   7762 
   7763 	st, err := r.Stat()
   7764 	if err != nil {
   7765 		logError(testName, function, args, startTime, "", "Stat failed", err)
   7766 		return
   7767 	}
   7768 
   7769 	if st.Size != int64(bufSize) {
   7770 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
   7771 		return
   7772 	}
   7773 
   7774 	offset := int64(2048)
   7775 	n, err := r.Seek(offset, 0)
   7776 	if err != nil {
   7777 		logError(testName, function, args, startTime, "", "Seek failed", err)
   7778 		return
   7779 	}
   7780 	if n != offset {
   7781 		logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset)+" got "+string(n), err)
   7782 		return
   7783 	}
   7784 	n, err = r.Seek(0, 1)
   7785 	if err != nil {
   7786 		logError(testName, function, args, startTime, "", "Seek failed", err)
   7787 		return
   7788 	}
   7789 	if n != offset {
   7790 		logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset)+" got "+string(n), err)
   7791 		return
   7792 	}
   7793 	_, err = r.Seek(offset, 2)
   7794 	if err == nil {
   7795 		logError(testName, function, args, startTime, "", "Seek on positive offset for whence '2' should error out", err)
   7796 		return
   7797 	}
   7798 	n, err = r.Seek(-offset, 2)
   7799 	if err != nil {
   7800 		logError(testName, function, args, startTime, "", "Seek failed", err)
   7801 		return
   7802 	}
   7803 	if n != st.Size-offset {
   7804 		logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(st.Size-offset)+" got "+string(n), err)
   7805 		return
   7806 	}
   7807 
   7808 	var buffer1 bytes.Buffer
   7809 	if _, err = io.CopyN(&buffer1, r, st.Size); err != nil {
   7810 		if err != io.EOF {
   7811 			logError(testName, function, args, startTime, "", "Copy failed", err)
   7812 			return
   7813 		}
   7814 	}
   7815 	if !bytes.Equal(buf[len(buf)-int(offset):], buffer1.Bytes()) {
   7816 		logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
   7817 		return
   7818 	}
   7819 
   7820 	// Seek again and read again.
   7821 	n, err = r.Seek(offset-1, 0)
   7822 	if err != nil {
   7823 		logError(testName, function, args, startTime, "", "Seek failed", err)
   7824 		return
   7825 	}
   7826 	if n != (offset - 1) {
   7827 		logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset-1)+" got "+string(n), err)
   7828 		return
   7829 	}
   7830 
   7831 	var buffer2 bytes.Buffer
   7832 	if _, err = io.CopyN(&buffer2, r, st.Size); err != nil {
   7833 		if err != io.EOF {
   7834 			logError(testName, function, args, startTime, "", "Copy failed", err)
   7835 			return
   7836 		}
   7837 	}
   7838 	// Verify now lesser bytes.
   7839 	if !bytes.Equal(buf[2047:], buffer2.Bytes()) {
   7840 		logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
   7841 		return
   7842 	}
   7843 
   7844 	successLogger(testName, function, args, startTime).Info()
   7845 }
   7846 
   7847 // Tests get object ReaderAt interface methods.
   7848 func testGetObjectReadAtFunctionalV2() {
   7849 	// initialize logging params
   7850 	startTime := time.Now()
   7851 	testName := getFuncName()
   7852 	function := "GetObject(bucketName, objectName)"
   7853 	args := map[string]interface{}{}
   7854 
   7855 	// Seed random based on current time.
   7856 	rand.Seed(time.Now().Unix())
   7857 
   7858 	// Instantiate new minio client object.
   7859 	c, err := minio.New(os.Getenv(serverEndpoint),
   7860 		&minio.Options{
   7861 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   7862 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   7863 		})
   7864 	if err != nil {
   7865 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   7866 		return
   7867 	}
   7868 
   7869 	// Enable tracing, write to stderr.
   7870 	// c.TraceOn(os.Stderr)
   7871 
   7872 	// Set user agent.
   7873 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   7874 
   7875 	// Generate a new random bucket name.
   7876 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   7877 	args["bucketName"] = bucketName
   7878 
   7879 	// Make a new bucket.
   7880 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   7881 	if err != nil {
   7882 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   7883 		return
   7884 	}
   7885 
   7886 	defer cleanupBucket(bucketName, c)
   7887 
   7888 	// Generate 33K of data.
   7889 	bufSize := dataFileMap["datafile-33-kB"]
   7890 	reader := getDataReader("datafile-33-kB")
   7891 	defer reader.Close()
   7892 
   7893 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   7894 	args["objectName"] = objectName
   7895 
   7896 	buf, err := io.ReadAll(reader)
   7897 	if err != nil {
   7898 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   7899 		return
   7900 	}
   7901 
   7902 	// Save the data
   7903 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   7904 	if err != nil {
   7905 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   7906 		return
   7907 	}
   7908 
   7909 	// Read the data back
   7910 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   7911 	if err != nil {
   7912 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   7913 		return
   7914 	}
   7915 	defer r.Close()
   7916 
   7917 	st, err := r.Stat()
   7918 	if err != nil {
   7919 		logError(testName, function, args, startTime, "", "Stat failed", err)
   7920 		return
   7921 	}
   7922 
   7923 	if st.Size != int64(bufSize) {
   7924 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
   7925 		return
   7926 	}
   7927 
   7928 	offset := int64(2048)
   7929 
   7930 	// Read directly
   7931 	buf2 := make([]byte, 512)
   7932 	buf3 := make([]byte, 512)
   7933 	buf4 := make([]byte, 512)
   7934 
   7935 	m, err := r.ReadAt(buf2, offset)
   7936 	if err != nil {
   7937 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   7938 		return
   7939 	}
   7940 	if m != len(buf2) {
   7941 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+" got "+string(m), err)
   7942 		return
   7943 	}
   7944 	if !bytes.Equal(buf2, buf[offset:offset+512]) {
   7945 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   7946 		return
   7947 	}
   7948 	offset += 512
   7949 	m, err = r.ReadAt(buf3, offset)
   7950 	if err != nil {
   7951 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   7952 		return
   7953 	}
   7954 	if m != len(buf3) {
   7955 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+" got "+string(m), err)
   7956 		return
   7957 	}
   7958 	if !bytes.Equal(buf3, buf[offset:offset+512]) {
   7959 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   7960 		return
   7961 	}
   7962 	offset += 512
   7963 	m, err = r.ReadAt(buf4, offset)
   7964 	if err != nil {
   7965 		logError(testName, function, args, startTime, "", "ReadAt failed", err)
   7966 		return
   7967 	}
   7968 	if m != len(buf4) {
   7969 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+" got "+string(m), err)
   7970 		return
   7971 	}
   7972 	if !bytes.Equal(buf4, buf[offset:offset+512]) {
   7973 		logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
   7974 		return
   7975 	}
   7976 
   7977 	buf5 := make([]byte, bufSize)
   7978 	// Read the whole object.
   7979 	m, err = r.ReadAt(buf5, 0)
   7980 	if err != nil {
   7981 		if err != io.EOF {
   7982 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   7983 			return
   7984 		}
   7985 	}
   7986 	if m != len(buf5) {
   7987 		logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+" got "+string(m), err)
   7988 		return
   7989 	}
   7990 	if !bytes.Equal(buf, buf5) {
   7991 		logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
   7992 		return
   7993 	}
   7994 
   7995 	buf6 := make([]byte, bufSize+1)
   7996 	// Read the whole object and beyond.
   7997 	_, err = r.ReadAt(buf6, 0)
   7998 	if err != nil {
   7999 		if err != io.EOF {
   8000 			logError(testName, function, args, startTime, "", "ReadAt failed", err)
   8001 			return
   8002 		}
   8003 	}
   8004 
   8005 	successLogger(testName, function, args, startTime).Info()
   8006 }
   8007 
   8008 // Tests copy object
   8009 func testCopyObjectV2() {
   8010 	// initialize logging params
   8011 	startTime := time.Now()
   8012 	testName := getFuncName()
   8013 	function := "CopyObject(destination, source)"
   8014 	args := map[string]interface{}{}
   8015 
   8016 	// Seed random based on current time.
   8017 	rand.Seed(time.Now().Unix())
   8018 
   8019 	// Instantiate new minio client object
   8020 	c, err := minio.New(os.Getenv(serverEndpoint),
   8021 		&minio.Options{
   8022 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8023 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8024 		})
   8025 	if err != nil {
   8026 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8027 		return
   8028 	}
   8029 
   8030 	// Enable tracing, write to stderr.
   8031 	// c.TraceOn(os.Stderr)
   8032 
   8033 	// Set user agent.
   8034 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   8035 
   8036 	// Generate a new random bucket name.
   8037 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8038 
   8039 	// Make a new bucket in 'us-east-1' (source bucket).
   8040 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8041 	if err != nil {
   8042 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8043 		return
   8044 	}
   8045 	defer cleanupBucket(bucketName, c)
   8046 
   8047 	// Make a new bucket in 'us-east-1' (destination bucket).
   8048 	err = c.MakeBucket(context.Background(), bucketName+"-copy", minio.MakeBucketOptions{Region: "us-east-1"})
   8049 	if err != nil {
   8050 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8051 		return
   8052 	}
   8053 	defer cleanupBucket(bucketName+"-copy", c)
   8054 
   8055 	// Generate 33K of data.
   8056 	bufSize := dataFileMap["datafile-33-kB"]
   8057 	reader := getDataReader("datafile-33-kB")
   8058 	defer reader.Close()
   8059 
   8060 	// Save the data
   8061 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   8062 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   8063 	if err != nil {
   8064 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   8065 		return
   8066 	}
   8067 
   8068 	r, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   8069 	if err != nil {
   8070 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8071 		return
   8072 	}
   8073 	// Check the various fields of source object against destination object.
   8074 	objInfo, err := r.Stat()
   8075 	if err != nil {
   8076 		logError(testName, function, args, startTime, "", "Stat failed", err)
   8077 		return
   8078 	}
   8079 	r.Close()
   8080 
   8081 	// Copy Source
   8082 	src := minio.CopySrcOptions{
   8083 		Bucket:             bucketName,
   8084 		Object:             objectName,
   8085 		MatchModifiedSince: time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC),
   8086 		MatchETag:          objInfo.ETag,
   8087 	}
   8088 	args["source"] = src
   8089 
   8090 	// Set copy conditions.
   8091 	dst := minio.CopyDestOptions{
   8092 		Bucket: bucketName + "-copy",
   8093 		Object: objectName + "-copy",
   8094 	}
   8095 	args["destination"] = dst
   8096 
   8097 	// Perform the Copy
   8098 	_, err = c.CopyObject(context.Background(), dst, src)
   8099 	if err != nil {
   8100 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
   8101 		return
   8102 	}
   8103 
   8104 	// Source object
   8105 	r, err = c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
   8106 	if err != nil {
   8107 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8108 		return
   8109 	}
   8110 	// Destination object
   8111 	readerCopy, err := c.GetObject(context.Background(), bucketName+"-copy", objectName+"-copy", minio.GetObjectOptions{})
   8112 	if err != nil {
   8113 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8114 		return
   8115 	}
   8116 	// Check the various fields of source object against destination object.
   8117 	objInfo, err = r.Stat()
   8118 	if err != nil {
   8119 		logError(testName, function, args, startTime, "", "Stat failed", err)
   8120 		return
   8121 	}
   8122 	objInfoCopy, err := readerCopy.Stat()
   8123 	if err != nil {
   8124 		logError(testName, function, args, startTime, "", "Stat failed", err)
   8125 		return
   8126 	}
   8127 	if objInfo.Size != objInfoCopy.Size {
   8128 		logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(objInfoCopy.Size)+" got "+string(objInfo.Size), err)
   8129 		return
   8130 	}
   8131 
   8132 	// Close all the readers.
   8133 	r.Close()
   8134 	readerCopy.Close()
   8135 
   8136 	// CopyObject again but with wrong conditions
   8137 	src = minio.CopySrcOptions{
   8138 		Bucket:               bucketName,
   8139 		Object:               objectName,
   8140 		MatchUnmodifiedSince: time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC),
   8141 		NoMatchETag:          objInfo.ETag,
   8142 	}
   8143 
   8144 	// Perform the Copy which should fail
   8145 	_, err = c.CopyObject(context.Background(), dst, src)
   8146 	if err == nil {
   8147 		logError(testName, function, args, startTime, "", "CopyObject did not fail for invalid conditions", err)
   8148 		return
   8149 	}
   8150 
   8151 	successLogger(testName, function, args, startTime).Info()
   8152 }
   8153 
   8154 func testComposeObjectErrorCasesWrapper(c *minio.Client) {
   8155 	// initialize logging params
   8156 	startTime := time.Now()
   8157 	testName := getFuncName()
   8158 	function := "ComposeObject(destination, sourceList)"
   8159 	args := map[string]interface{}{}
   8160 
   8161 	// Generate a new random bucket name.
   8162 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8163 
   8164 	// Make a new bucket in 'us-east-1' (source bucket).
   8165 	err := c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8166 	if err != nil {
   8167 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8168 		return
   8169 	}
   8170 
   8171 	defer cleanupBucket(bucketName, c)
   8172 
   8173 	// Test that more than 10K source objects cannot be
   8174 	// concatenated.
   8175 	srcArr := [10001]minio.CopySrcOptions{}
   8176 	srcSlice := srcArr[:]
   8177 	dst := minio.CopyDestOptions{
   8178 		Bucket: bucketName,
   8179 		Object: "object",
   8180 	}
   8181 
   8182 	args["destination"] = dst
   8183 	// Just explain about srcArr in args["sourceList"]
   8184 	// to stop having 10,001 null headers logged
   8185 	args["sourceList"] = "source array of 10,001 elements"
   8186 	if _, err := c.ComposeObject(context.Background(), dst, srcSlice...); err == nil {
   8187 		logError(testName, function, args, startTime, "", "Expected error in ComposeObject", err)
   8188 		return
   8189 	} else if err.Error() != "There must be as least one and up to 10000 source objects." {
   8190 		logError(testName, function, args, startTime, "", "Got unexpected error", err)
   8191 		return
   8192 	}
   8193 
   8194 	// Create a source with invalid offset spec and check that
   8195 	// error is returned:
   8196 	// 1. Create the source object.
   8197 	const badSrcSize = 5 * 1024 * 1024
   8198 	buf := bytes.Repeat([]byte("1"), badSrcSize)
   8199 	_, err = c.PutObject(context.Background(), bucketName, "badObject", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
   8200 	if err != nil {
   8201 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   8202 		return
   8203 	}
   8204 	// 2. Set invalid range spec on the object (going beyond
   8205 	// object size)
   8206 	badSrc := minio.CopySrcOptions{
   8207 		Bucket:     bucketName,
   8208 		Object:     "badObject",
   8209 		MatchRange: true,
   8210 		Start:      1,
   8211 		End:        badSrcSize,
   8212 	}
   8213 
   8214 	// 3. ComposeObject call should fail.
   8215 	if _, err := c.ComposeObject(context.Background(), dst, badSrc); err == nil {
   8216 		logError(testName, function, args, startTime, "", "ComposeObject expected to fail", err)
   8217 		return
   8218 	} else if !strings.Contains(err.Error(), "has invalid segment-to-copy") {
   8219 		logError(testName, function, args, startTime, "", "Got invalid error", err)
   8220 		return
   8221 	}
   8222 
   8223 	successLogger(testName, function, args, startTime).Info()
   8224 }
   8225 
   8226 // Test expected error cases
   8227 func testComposeObjectErrorCasesV2() {
   8228 	// initialize logging params
   8229 	startTime := time.Now()
   8230 	testName := getFuncName()
   8231 	function := "ComposeObject(destination, sourceList)"
   8232 	args := map[string]interface{}{}
   8233 
   8234 	// Instantiate new minio client object
   8235 	c, err := minio.New(os.Getenv(serverEndpoint),
   8236 		&minio.Options{
   8237 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8238 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8239 		})
   8240 	if err != nil {
   8241 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8242 		return
   8243 	}
   8244 
   8245 	testComposeObjectErrorCasesWrapper(c)
   8246 }
   8247 
   8248 func testComposeMultipleSources(c *minio.Client) {
   8249 	// initialize logging params
   8250 	startTime := time.Now()
   8251 	testName := getFuncName()
   8252 	function := "ComposeObject(destination, sourceList)"
   8253 	args := map[string]interface{}{
   8254 		"destination": "",
   8255 		"sourceList":  "",
   8256 	}
   8257 
   8258 	// Generate a new random bucket name.
   8259 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8260 	// Make a new bucket in 'us-east-1' (source bucket).
   8261 	err := c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8262 	if err != nil {
   8263 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8264 		return
   8265 	}
   8266 
   8267 	defer cleanupBucket(bucketName, c)
   8268 
   8269 	// Upload a small source object
   8270 	const srcSize = 1024 * 1024 * 5
   8271 	buf := bytes.Repeat([]byte("1"), srcSize)
   8272 	_, err = c.PutObject(context.Background(), bucketName, "srcObject", bytes.NewReader(buf), int64(srcSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
   8273 	if err != nil {
   8274 		logError(testName, function, args, startTime, "", "PutObject failed", err)
   8275 		return
   8276 	}
   8277 
   8278 	// We will append 10 copies of the object.
   8279 	srcs := []minio.CopySrcOptions{}
   8280 	for i := 0; i < 10; i++ {
   8281 		srcs = append(srcs, minio.CopySrcOptions{
   8282 			Bucket: bucketName,
   8283 			Object: "srcObject",
   8284 		})
   8285 	}
   8286 
   8287 	// make the last part very small
   8288 	srcs[9].MatchRange = true
   8289 
   8290 	args["sourceList"] = srcs
   8291 
   8292 	dst := minio.CopyDestOptions{
   8293 		Bucket: bucketName,
   8294 		Object: "dstObject",
   8295 	}
   8296 	args["destination"] = dst
   8297 
   8298 	ui, err := c.ComposeObject(context.Background(), dst, srcs...)
   8299 	if err != nil {
   8300 		logError(testName, function, args, startTime, "", "ComposeObject failed", err)
   8301 		return
   8302 	}
   8303 
   8304 	if ui.Size != 9*srcSize+1 {
   8305 		logError(testName, function, args, startTime, "", "ComposeObject returned unexpected size", err)
   8306 		return
   8307 	}
   8308 
   8309 	objProps, err := c.StatObject(context.Background(), bucketName, "dstObject", minio.StatObjectOptions{})
   8310 	if err != nil {
   8311 		logError(testName, function, args, startTime, "", "StatObject failed", err)
   8312 		return
   8313 	}
   8314 
   8315 	if objProps.Size != 9*srcSize+1 {
   8316 		logError(testName, function, args, startTime, "", "Size mismatched! Expected "+string(10000*srcSize)+" got "+string(objProps.Size), err)
   8317 		return
   8318 	}
   8319 
   8320 	successLogger(testName, function, args, startTime).Info()
   8321 }
   8322 
   8323 // Test concatenating multiple 10K objects V2
   8324 func testCompose10KSourcesV2() {
   8325 	// initialize logging params
   8326 	startTime := time.Now()
   8327 	testName := getFuncName()
   8328 	function := "ComposeObject(destination, sourceList)"
   8329 	args := map[string]interface{}{}
   8330 
   8331 	// Instantiate new minio client object
   8332 	c, err := minio.New(os.Getenv(serverEndpoint),
   8333 		&minio.Options{
   8334 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8335 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8336 		})
   8337 	if err != nil {
   8338 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8339 		return
   8340 	}
   8341 
   8342 	testComposeMultipleSources(c)
   8343 }
   8344 
   8345 func testEncryptedEmptyObject() {
   8346 	// initialize logging params
   8347 	startTime := time.Now()
   8348 	testName := getFuncName()
   8349 	function := "PutObject(bucketName, objectName, reader, objectSize, opts)"
   8350 	args := map[string]interface{}{}
   8351 
   8352 	// Instantiate new minio client object
   8353 	c, err := minio.New(os.Getenv(serverEndpoint),
   8354 		&minio.Options{
   8355 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8356 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8357 		})
   8358 	if err != nil {
   8359 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   8360 		return
   8361 	}
   8362 
   8363 	// Generate a new random bucket name.
   8364 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8365 	args["bucketName"] = bucketName
   8366 	// Make a new bucket in 'us-east-1' (source bucket).
   8367 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8368 	if err != nil {
   8369 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8370 		return
   8371 	}
   8372 
   8373 	defer cleanupBucket(bucketName, c)
   8374 
   8375 	sse := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"object"))
   8376 
   8377 	// 1. create an sse-c encrypted object to copy by uploading
   8378 	const srcSize = 0
   8379 	var buf []byte // Empty buffer
   8380 	args["objectName"] = "object"
   8381 	_, err = c.PutObject(context.Background(), bucketName, "object", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ServerSideEncryption: sse})
   8382 	if err != nil {
   8383 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   8384 		return
   8385 	}
   8386 
   8387 	// 2. Test CopyObject for an empty object
   8388 	src := minio.CopySrcOptions{
   8389 		Bucket:     bucketName,
   8390 		Object:     "object",
   8391 		Encryption: sse,
   8392 	}
   8393 
   8394 	dst := minio.CopyDestOptions{
   8395 		Bucket:     bucketName,
   8396 		Object:     "new-object",
   8397 		Encryption: sse,
   8398 	}
   8399 
   8400 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
   8401 		function = "CopyObject(dst, src)"
   8402 		logError(testName, function, map[string]interface{}{}, startTime, "", "CopyObject failed", err)
   8403 		return
   8404 	}
   8405 
   8406 	// 3. Test Key rotation
   8407 	newSSE := encrypt.DefaultPBKDF([]byte("Don't Panic"), []byte(bucketName+"new-object"))
   8408 	src = minio.CopySrcOptions{
   8409 		Bucket:     bucketName,
   8410 		Object:     "new-object",
   8411 		Encryption: sse,
   8412 	}
   8413 
   8414 	dst = minio.CopyDestOptions{
   8415 		Bucket:     bucketName,
   8416 		Object:     "new-object",
   8417 		Encryption: newSSE,
   8418 	}
   8419 
   8420 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
   8421 		function = "CopyObject(dst, src)"
   8422 		logError(testName, function, map[string]interface{}{}, startTime, "", "CopyObject with key rotation failed", err)
   8423 		return
   8424 	}
   8425 
   8426 	// 4. Download the object.
   8427 	reader, err := c.GetObject(context.Background(), bucketName, "new-object", minio.GetObjectOptions{ServerSideEncryption: newSSE})
   8428 	if err != nil {
   8429 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8430 		return
   8431 	}
   8432 	defer reader.Close()
   8433 
   8434 	decBytes, err := io.ReadAll(reader)
   8435 	if err != nil {
   8436 		logError(testName, function, map[string]interface{}{}, startTime, "", "ReadAll failed", err)
   8437 		return
   8438 	}
   8439 	if !bytes.Equal(decBytes, buf) {
   8440 		logError(testName, function, map[string]interface{}{}, startTime, "", "Downloaded object doesn't match the empty encrypted object", err)
   8441 		return
   8442 	}
   8443 
   8444 	delete(args, "objectName")
   8445 	successLogger(testName, function, args, startTime).Info()
   8446 }
   8447 
   8448 func testEncryptedCopyObjectWrapper(c *minio.Client, bucketName string, sseSrc, sseDst encrypt.ServerSide) {
   8449 	// initialize logging params
   8450 	startTime := time.Now()
   8451 	testName := getFuncNameLoc(2)
   8452 	function := "CopyObject(destination, source)"
   8453 	args := map[string]interface{}{}
   8454 	var srcEncryption, dstEncryption encrypt.ServerSide
   8455 
   8456 	// Make a new bucket in 'us-east-1' (source bucket).
   8457 	err := c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8458 	if err != nil {
   8459 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8460 		return
   8461 	}
   8462 
   8463 	defer cleanupBucket(bucketName, c)
   8464 
   8465 	// 1. create an sse-c encrypted object to copy by uploading
   8466 	const srcSize = 1024 * 1024
   8467 	buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 5MiB
   8468 	_, err = c.PutObject(context.Background(), bucketName, "srcObject", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{
   8469 		ServerSideEncryption: sseSrc,
   8470 	})
   8471 	if err != nil {
   8472 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   8473 		return
   8474 	}
   8475 
   8476 	if sseSrc != nil && sseSrc.Type() != encrypt.S3 {
   8477 		srcEncryption = sseSrc
   8478 	}
   8479 
   8480 	// 2. copy object and change encryption key
   8481 	src := minio.CopySrcOptions{
   8482 		Bucket:     bucketName,
   8483 		Object:     "srcObject",
   8484 		Encryption: srcEncryption,
   8485 	}
   8486 	args["source"] = src
   8487 
   8488 	dst := minio.CopyDestOptions{
   8489 		Bucket:     bucketName,
   8490 		Object:     "dstObject",
   8491 		Encryption: sseDst,
   8492 	}
   8493 	args["destination"] = dst
   8494 
   8495 	_, err = c.CopyObject(context.Background(), dst, src)
   8496 	if err != nil {
   8497 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
   8498 		return
   8499 	}
   8500 
   8501 	if sseDst != nil && sseDst.Type() != encrypt.S3 {
   8502 		dstEncryption = sseDst
   8503 	}
   8504 	// 3. get copied object and check if content is equal
   8505 	coreClient := minio.Core{c}
   8506 	reader, _, _, err := coreClient.GetObject(context.Background(), bucketName, "dstObject", minio.GetObjectOptions{ServerSideEncryption: dstEncryption})
   8507 	if err != nil {
   8508 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8509 		return
   8510 	}
   8511 
   8512 	decBytes, err := io.ReadAll(reader)
   8513 	if err != nil {
   8514 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   8515 		return
   8516 	}
   8517 	if !bytes.Equal(decBytes, buf) {
   8518 		logError(testName, function, args, startTime, "", "Downloaded object mismatched for encrypted object", err)
   8519 		return
   8520 	}
   8521 	reader.Close()
   8522 
   8523 	// Test key rotation for source object in-place.
   8524 	var newSSE encrypt.ServerSide
   8525 	if sseSrc != nil && sseSrc.Type() == encrypt.SSEC {
   8526 		newSSE = encrypt.DefaultPBKDF([]byte("Don't Panic"), []byte(bucketName+"srcObject")) // replace key
   8527 	}
   8528 	if sseSrc != nil && sseSrc.Type() == encrypt.S3 {
   8529 		newSSE = encrypt.NewSSE()
   8530 	}
   8531 	if newSSE != nil {
   8532 		dst = minio.CopyDestOptions{
   8533 			Bucket:     bucketName,
   8534 			Object:     "srcObject",
   8535 			Encryption: newSSE,
   8536 		}
   8537 		args["destination"] = dst
   8538 
   8539 		_, err = c.CopyObject(context.Background(), dst, src)
   8540 		if err != nil {
   8541 			logError(testName, function, args, startTime, "", "CopyObject failed", err)
   8542 			return
   8543 		}
   8544 
   8545 		// Get copied object and check if content is equal
   8546 		reader, _, _, err = coreClient.GetObject(context.Background(), bucketName, "srcObject", minio.GetObjectOptions{ServerSideEncryption: newSSE})
   8547 		if err != nil {
   8548 			logError(testName, function, args, startTime, "", "GetObject failed", err)
   8549 			return
   8550 		}
   8551 
   8552 		decBytes, err = io.ReadAll(reader)
   8553 		if err != nil {
   8554 			logError(testName, function, args, startTime, "", "ReadAll failed", err)
   8555 			return
   8556 		}
   8557 		if !bytes.Equal(decBytes, buf) {
   8558 			logError(testName, function, args, startTime, "", "Downloaded object mismatched for encrypted object", err)
   8559 			return
   8560 		}
   8561 		reader.Close()
   8562 
   8563 		// Test in-place decryption.
   8564 		dst = minio.CopyDestOptions{
   8565 			Bucket: bucketName,
   8566 			Object: "srcObject",
   8567 		}
   8568 		args["destination"] = dst
   8569 
   8570 		src = minio.CopySrcOptions{
   8571 			Bucket:     bucketName,
   8572 			Object:     "srcObject",
   8573 			Encryption: newSSE,
   8574 		}
   8575 		args["source"] = src
   8576 		_, err = c.CopyObject(context.Background(), dst, src)
   8577 		if err != nil {
   8578 			logError(testName, function, args, startTime, "", "CopyObject Key rotation failed", err)
   8579 			return
   8580 		}
   8581 	}
   8582 
   8583 	// Get copied decrypted object and check if content is equal
   8584 	reader, _, _, err = coreClient.GetObject(context.Background(), bucketName, "srcObject", minio.GetObjectOptions{})
   8585 	if err != nil {
   8586 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8587 		return
   8588 	}
   8589 	defer reader.Close()
   8590 
   8591 	decBytes, err = io.ReadAll(reader)
   8592 	if err != nil {
   8593 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
   8594 		return
   8595 	}
   8596 	if !bytes.Equal(decBytes, buf) {
   8597 		logError(testName, function, args, startTime, "", "Downloaded object mismatched for encrypted object", err)
   8598 		return
   8599 	}
   8600 
   8601 	successLogger(testName, function, args, startTime).Info()
   8602 }
   8603 
   8604 // Test encrypted copy object
   8605 func testUnencryptedToSSECCopyObject() {
   8606 	// initialize logging params
   8607 	startTime := time.Now()
   8608 	testName := getFuncName()
   8609 	function := "CopyObject(destination, source)"
   8610 	args := map[string]interface{}{}
   8611 
   8612 	// Instantiate new minio client object
   8613 	c, err := minio.New(os.Getenv(serverEndpoint),
   8614 		&minio.Options{
   8615 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8616 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8617 		})
   8618 	if err != nil {
   8619 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8620 		return
   8621 	}
   8622 	// Generate a new random bucket name.
   8623 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8624 
   8625 	sseDst := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"dstObject"))
   8626 	// c.TraceOn(os.Stderr)
   8627 	testEncryptedCopyObjectWrapper(c, bucketName, nil, sseDst)
   8628 }
   8629 
   8630 // Test encrypted copy object
   8631 func testUnencryptedToSSES3CopyObject() {
   8632 	// initialize logging params
   8633 	startTime := time.Now()
   8634 	testName := getFuncName()
   8635 	function := "CopyObject(destination, source)"
   8636 	args := map[string]interface{}{}
   8637 
   8638 	// Instantiate new minio client object
   8639 	c, err := minio.New(os.Getenv(serverEndpoint),
   8640 		&minio.Options{
   8641 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8642 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8643 		})
   8644 	if err != nil {
   8645 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8646 		return
   8647 	}
   8648 	// Generate a new random bucket name.
   8649 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8650 
   8651 	var sseSrc encrypt.ServerSide
   8652 	sseDst := encrypt.NewSSE()
   8653 	// c.TraceOn(os.Stderr)
   8654 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8655 }
   8656 
   8657 // Test encrypted copy object
   8658 func testUnencryptedToUnencryptedCopyObject() {
   8659 	// initialize logging params
   8660 	startTime := time.Now()
   8661 	testName := getFuncName()
   8662 	function := "CopyObject(destination, source)"
   8663 	args := map[string]interface{}{}
   8664 
   8665 	// Instantiate new minio client object
   8666 	c, err := minio.New(os.Getenv(serverEndpoint),
   8667 		&minio.Options{
   8668 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8669 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8670 		})
   8671 	if err != nil {
   8672 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8673 		return
   8674 	}
   8675 	// Generate a new random bucket name.
   8676 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8677 
   8678 	var sseSrc, sseDst encrypt.ServerSide
   8679 	// c.TraceOn(os.Stderr)
   8680 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8681 }
   8682 
   8683 // Test encrypted copy object
   8684 func testEncryptedSSECToSSECCopyObject() {
   8685 	// initialize logging params
   8686 	startTime := time.Now()
   8687 	testName := getFuncName()
   8688 	function := "CopyObject(destination, source)"
   8689 	args := map[string]interface{}{}
   8690 
   8691 	// Instantiate new minio client object
   8692 	c, err := minio.New(os.Getenv(serverEndpoint),
   8693 		&minio.Options{
   8694 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8695 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8696 		})
   8697 	if err != nil {
   8698 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8699 		return
   8700 	}
   8701 	// Generate a new random bucket name.
   8702 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8703 
   8704 	sseSrc := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"srcObject"))
   8705 	sseDst := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"dstObject"))
   8706 	// c.TraceOn(os.Stderr)
   8707 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8708 }
   8709 
   8710 // Test encrypted copy object
   8711 func testEncryptedSSECToSSES3CopyObject() {
   8712 	// initialize logging params
   8713 	startTime := time.Now()
   8714 	testName := getFuncName()
   8715 	function := "CopyObject(destination, source)"
   8716 	args := map[string]interface{}{}
   8717 
   8718 	// Instantiate new minio client object
   8719 	c, err := minio.New(os.Getenv(serverEndpoint),
   8720 		&minio.Options{
   8721 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8722 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8723 		})
   8724 	if err != nil {
   8725 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8726 		return
   8727 	}
   8728 	// Generate a new random bucket name.
   8729 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8730 
   8731 	sseSrc := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"srcObject"))
   8732 	sseDst := encrypt.NewSSE()
   8733 	// c.TraceOn(os.Stderr)
   8734 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8735 }
   8736 
   8737 // Test encrypted copy object
   8738 func testEncryptedSSECToUnencryptedCopyObject() {
   8739 	// initialize logging params
   8740 	startTime := time.Now()
   8741 	testName := getFuncName()
   8742 	function := "CopyObject(destination, source)"
   8743 	args := map[string]interface{}{}
   8744 
   8745 	// Instantiate new minio client object
   8746 	c, err := minio.New(os.Getenv(serverEndpoint),
   8747 		&minio.Options{
   8748 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8749 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8750 		})
   8751 	if err != nil {
   8752 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8753 		return
   8754 	}
   8755 	// Generate a new random bucket name.
   8756 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8757 
   8758 	sseSrc := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"srcObject"))
   8759 	var sseDst encrypt.ServerSide
   8760 	// c.TraceOn(os.Stderr)
   8761 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8762 }
   8763 
   8764 // Test encrypted copy object
   8765 func testEncryptedSSES3ToSSECCopyObject() {
   8766 	// initialize logging params
   8767 	startTime := time.Now()
   8768 	testName := getFuncName()
   8769 	function := "CopyObject(destination, source)"
   8770 	args := map[string]interface{}{}
   8771 
   8772 	// Instantiate new minio client object
   8773 	c, err := minio.New(os.Getenv(serverEndpoint),
   8774 		&minio.Options{
   8775 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8776 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8777 		})
   8778 	if err != nil {
   8779 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8780 		return
   8781 	}
   8782 	// Generate a new random bucket name.
   8783 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8784 
   8785 	sseSrc := encrypt.NewSSE()
   8786 	sseDst := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"dstObject"))
   8787 	// c.TraceOn(os.Stderr)
   8788 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8789 }
   8790 
   8791 // Test encrypted copy object
   8792 func testEncryptedSSES3ToSSES3CopyObject() {
   8793 	// initialize logging params
   8794 	startTime := time.Now()
   8795 	testName := getFuncName()
   8796 	function := "CopyObject(destination, source)"
   8797 	args := map[string]interface{}{}
   8798 
   8799 	// Instantiate new minio client object
   8800 	c, err := minio.New(os.Getenv(serverEndpoint),
   8801 		&minio.Options{
   8802 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8803 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8804 		})
   8805 	if err != nil {
   8806 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8807 		return
   8808 	}
   8809 	// Generate a new random bucket name.
   8810 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8811 
   8812 	sseSrc := encrypt.NewSSE()
   8813 	sseDst := encrypt.NewSSE()
   8814 	// c.TraceOn(os.Stderr)
   8815 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8816 }
   8817 
   8818 // Test encrypted copy object
   8819 func testEncryptedSSES3ToUnencryptedCopyObject() {
   8820 	// initialize logging params
   8821 	startTime := time.Now()
   8822 	testName := getFuncName()
   8823 	function := "CopyObject(destination, source)"
   8824 	args := map[string]interface{}{}
   8825 
   8826 	// Instantiate new minio client object
   8827 	c, err := minio.New(os.Getenv(serverEndpoint),
   8828 		&minio.Options{
   8829 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8830 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8831 		})
   8832 	if err != nil {
   8833 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8834 		return
   8835 	}
   8836 	// Generate a new random bucket name.
   8837 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8838 
   8839 	sseSrc := encrypt.NewSSE()
   8840 	var sseDst encrypt.ServerSide
   8841 	// c.TraceOn(os.Stderr)
   8842 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8843 }
   8844 
   8845 // Test encrypted copy object
   8846 func testEncryptedCopyObjectV2() {
   8847 	// initialize logging params
   8848 	startTime := time.Now()
   8849 	testName := getFuncName()
   8850 	function := "CopyObject(destination, source)"
   8851 	args := map[string]interface{}{}
   8852 
   8853 	// Instantiate new minio client object
   8854 	c, err := minio.New(os.Getenv(serverEndpoint),
   8855 		&minio.Options{
   8856 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8857 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8858 		})
   8859 	if err != nil {
   8860 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8861 		return
   8862 	}
   8863 	// Generate a new random bucket name.
   8864 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
   8865 
   8866 	sseSrc := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"srcObject"))
   8867 	sseDst := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+"dstObject"))
   8868 	// c.TraceOn(os.Stderr)
   8869 	testEncryptedCopyObjectWrapper(c, bucketName, sseSrc, sseDst)
   8870 }
   8871 
   8872 func testDecryptedCopyObject() {
   8873 	// initialize logging params
   8874 	startTime := time.Now()
   8875 	testName := getFuncName()
   8876 	function := "CopyObject(destination, source)"
   8877 	args := map[string]interface{}{}
   8878 
   8879 	// Instantiate new minio client object
   8880 	c, err := minio.New(os.Getenv(serverEndpoint),
   8881 		&minio.Options{
   8882 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8883 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8884 		})
   8885 	if err != nil {
   8886 		logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
   8887 		return
   8888 	}
   8889 
   8890 	bucketName, objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-"), "object"
   8891 	if err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"}); err != nil {
   8892 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8893 		return
   8894 	}
   8895 
   8896 	defer cleanupBucket(bucketName, c)
   8897 
   8898 	encryption := encrypt.DefaultPBKDF([]byte("correct horse battery staple"), []byte(bucketName+objectName))
   8899 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(bytes.Repeat([]byte("a"), 1024*1024)), 1024*1024, minio.PutObjectOptions{
   8900 		ServerSideEncryption: encryption,
   8901 	})
   8902 	if err != nil {
   8903 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   8904 		return
   8905 	}
   8906 
   8907 	src := minio.CopySrcOptions{
   8908 		Bucket:     bucketName,
   8909 		Object:     objectName,
   8910 		Encryption: encrypt.SSECopy(encryption),
   8911 	}
   8912 	args["source"] = src
   8913 
   8914 	dst := minio.CopyDestOptions{
   8915 		Bucket: bucketName,
   8916 		Object: "decrypted-" + objectName,
   8917 	}
   8918 	args["destination"] = dst
   8919 
   8920 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
   8921 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
   8922 		return
   8923 	}
   8924 	if _, err = c.GetObject(context.Background(), bucketName, "decrypted-"+objectName, minio.GetObjectOptions{}); err != nil {
   8925 		logError(testName, function, args, startTime, "", "GetObject failed", err)
   8926 		return
   8927 	}
   8928 	successLogger(testName, function, args, startTime).Info()
   8929 }
   8930 
   8931 func testSSECMultipartEncryptedToSSECCopyObjectPart() {
   8932 	// initialize logging params
   8933 	startTime := time.Now()
   8934 	testName := getFuncName()
   8935 	function := "CopyObjectPart(destination, source)"
   8936 	args := map[string]interface{}{}
   8937 
   8938 	// Instantiate new minio client object
   8939 	client, err := minio.New(os.Getenv(serverEndpoint),
   8940 		&minio.Options{
   8941 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   8942 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   8943 		})
   8944 	if err != nil {
   8945 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   8946 		return
   8947 	}
   8948 
   8949 	// Instantiate new core client object.
   8950 	c := minio.Core{client}
   8951 
   8952 	// Enable tracing, write to stderr.
   8953 	// c.TraceOn(os.Stderr)
   8954 
   8955 	// Set user agent.
   8956 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   8957 
   8958 	// Generate a new random bucket name.
   8959 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   8960 
   8961 	// Make a new bucket.
   8962 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   8963 	if err != nil {
   8964 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   8965 		return
   8966 	}
   8967 	defer cleanupBucket(bucketName, client)
   8968 	// Make a buffer with 6MB of data
   8969 	buf := bytes.Repeat([]byte("abcdef"), 1024*1024)
   8970 
   8971 	// Save the data
   8972 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   8973 	password := "correct horse battery staple"
   8974 	srcencryption := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   8975 
   8976 	// Upload a 6MB object using multipart mechanism
   8977 	uploadID, err := c.NewMultipartUpload(context.Background(), bucketName, objectName, minio.PutObjectOptions{ServerSideEncryption: srcencryption})
   8978 	if err != nil {
   8979 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   8980 		return
   8981 	}
   8982 
   8983 	var completeParts []minio.CompletePart
   8984 
   8985 	part, err := c.PutObjectPart(context.Background(), bucketName, objectName, uploadID, 1,
   8986 		bytes.NewReader(buf[:5*1024*1024]), 5*1024*1024,
   8987 		minio.PutObjectPartOptions{SSE: srcencryption},
   8988 	)
   8989 	if err != nil {
   8990 		logError(testName, function, args, startTime, "", "PutObjectPart call failed", err)
   8991 		return
   8992 	}
   8993 	completeParts = append(completeParts, minio.CompletePart{PartNumber: part.PartNumber, ETag: part.ETag})
   8994 
   8995 	part, err = c.PutObjectPart(context.Background(), bucketName, objectName, uploadID, 2,
   8996 		bytes.NewReader(buf[5*1024*1024:]), 1024*1024,
   8997 		minio.PutObjectPartOptions{SSE: srcencryption},
   8998 	)
   8999 	if err != nil {
   9000 		logError(testName, function, args, startTime, "", "PutObjectPart call failed", err)
   9001 		return
   9002 	}
   9003 	completeParts = append(completeParts, minio.CompletePart{PartNumber: part.PartNumber, ETag: part.ETag})
   9004 
   9005 	// Complete the multipart upload
   9006 	_, err = c.CompleteMultipartUpload(context.Background(), bucketName, objectName, uploadID, completeParts, minio.PutObjectOptions{})
   9007 	if err != nil {
   9008 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9009 		return
   9010 	}
   9011 
   9012 	// Stat the object and check its length matches
   9013 	objInfo, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcencryption})
   9014 	if err != nil {
   9015 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9016 		return
   9017 	}
   9018 
   9019 	destBucketName := bucketName
   9020 	destObjectName := objectName + "-dest"
   9021 	dstencryption := encrypt.DefaultPBKDF([]byte(password), []byte(destBucketName+destObjectName))
   9022 
   9023 	uploadID, err = c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
   9024 	if err != nil {
   9025 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9026 		return
   9027 	}
   9028 
   9029 	// Content of the destination object will be two copies of
   9030 	// `objectName` concatenated, followed by first byte of
   9031 	// `objectName`.
   9032 	metadata := make(map[string]string)
   9033 	header := make(http.Header)
   9034 	encrypt.SSECopy(srcencryption).Marshal(header)
   9035 	dstencryption.Marshal(header)
   9036 	for k, v := range header {
   9037 		metadata[k] = v[0]
   9038 	}
   9039 
   9040 	metadata["x-amz-copy-source-if-match"] = objInfo.ETag
   9041 
   9042 	// First of three parts
   9043 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9044 	if err != nil {
   9045 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9046 		return
   9047 	}
   9048 
   9049 	// Second of three parts
   9050 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9051 	if err != nil {
   9052 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9053 		return
   9054 	}
   9055 
   9056 	// Last of three parts
   9057 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9058 	if err != nil {
   9059 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9060 		return
   9061 	}
   9062 
   9063 	// Complete the multipart upload
   9064 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9065 	if err != nil {
   9066 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9067 		return
   9068 	}
   9069 
   9070 	// Stat the object and check its length matches
   9071 	objInfo, err = c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{ServerSideEncryption: dstencryption})
   9072 	if err != nil {
   9073 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9074 		return
   9075 	}
   9076 
   9077 	if objInfo.Size != (6*1024*1024)*2+1 {
   9078 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9079 		return
   9080 	}
   9081 
   9082 	// Now we read the data back
   9083 	getOpts := minio.GetObjectOptions{ServerSideEncryption: dstencryption}
   9084 	getOpts.SetRange(0, 6*1024*1024-1)
   9085 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9086 	if err != nil {
   9087 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9088 		return
   9089 	}
   9090 	getBuf := make([]byte, 6*1024*1024)
   9091 	_, err = readFull(r, getBuf)
   9092 	if err != nil {
   9093 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9094 		return
   9095 	}
   9096 	if !bytes.Equal(getBuf, buf) {
   9097 		logError(testName, function, args, startTime, "", "Got unexpected data in first 6MB", err)
   9098 		return
   9099 	}
   9100 
   9101 	getOpts.SetRange(6*1024*1024, 0)
   9102 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9103 	if err != nil {
   9104 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9105 		return
   9106 	}
   9107 	getBuf = make([]byte, 6*1024*1024+1)
   9108 	_, err = readFull(r, getBuf)
   9109 	if err != nil {
   9110 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9111 		return
   9112 	}
   9113 	if !bytes.Equal(getBuf[:6*1024*1024], buf) {
   9114 		logError(testName, function, args, startTime, "", "Got unexpected data in second 6MB", err)
   9115 		return
   9116 	}
   9117 	if getBuf[6*1024*1024] != buf[0] {
   9118 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9119 		return
   9120 	}
   9121 
   9122 	successLogger(testName, function, args, startTime).Info()
   9123 
   9124 	// Do not need to remove destBucketName its same as bucketName.
   9125 }
   9126 
   9127 // Test Core CopyObjectPart implementation
   9128 func testSSECEncryptedToSSECCopyObjectPart() {
   9129 	// initialize logging params
   9130 	startTime := time.Now()
   9131 	testName := getFuncName()
   9132 	function := "CopyObjectPart(destination, source)"
   9133 	args := map[string]interface{}{}
   9134 
   9135 	// Instantiate new minio client object
   9136 	client, err := minio.New(os.Getenv(serverEndpoint),
   9137 		&minio.Options{
   9138 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   9139 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   9140 		})
   9141 	if err != nil {
   9142 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   9143 		return
   9144 	}
   9145 
   9146 	// Instantiate new core client object.
   9147 	c := minio.Core{client}
   9148 
   9149 	// Enable tracing, write to stderr.
   9150 	// c.TraceOn(os.Stderr)
   9151 
   9152 	// Set user agent.
   9153 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   9154 
   9155 	// Generate a new random bucket name.
   9156 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   9157 
   9158 	// Make a new bucket.
   9159 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   9160 	if err != nil {
   9161 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   9162 		return
   9163 	}
   9164 	defer cleanupBucket(bucketName, client)
   9165 	// Make a buffer with 5MB of data
   9166 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
   9167 
   9168 	// Save the data
   9169 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   9170 	password := "correct horse battery staple"
   9171 	srcencryption := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   9172 	putmetadata := map[string]string{
   9173 		"Content-Type": "binary/octet-stream",
   9174 	}
   9175 	opts := minio.PutObjectOptions{
   9176 		UserMetadata:         putmetadata,
   9177 		ServerSideEncryption: srcencryption,
   9178 	}
   9179 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
   9180 	if err != nil {
   9181 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   9182 		return
   9183 	}
   9184 
   9185 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcencryption})
   9186 	if err != nil {
   9187 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9188 		return
   9189 	}
   9190 
   9191 	if st.Size != int64(len(buf)) {
   9192 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
   9193 		return
   9194 	}
   9195 
   9196 	destBucketName := bucketName
   9197 	destObjectName := objectName + "-dest"
   9198 	dstencryption := encrypt.DefaultPBKDF([]byte(password), []byte(destBucketName+destObjectName))
   9199 
   9200 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
   9201 	if err != nil {
   9202 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9203 		return
   9204 	}
   9205 
   9206 	// Content of the destination object will be two copies of
   9207 	// `objectName` concatenated, followed by first byte of
   9208 	// `objectName`.
   9209 	metadata := make(map[string]string)
   9210 	header := make(http.Header)
   9211 	encrypt.SSECopy(srcencryption).Marshal(header)
   9212 	dstencryption.Marshal(header)
   9213 	for k, v := range header {
   9214 		metadata[k] = v[0]
   9215 	}
   9216 
   9217 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
   9218 
   9219 	// First of three parts
   9220 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9221 	if err != nil {
   9222 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9223 		return
   9224 	}
   9225 
   9226 	// Second of three parts
   9227 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9228 	if err != nil {
   9229 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9230 		return
   9231 	}
   9232 
   9233 	// Last of three parts
   9234 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9235 	if err != nil {
   9236 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9237 		return
   9238 	}
   9239 
   9240 	// Complete the multipart upload
   9241 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9242 	if err != nil {
   9243 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9244 		return
   9245 	}
   9246 
   9247 	// Stat the object and check its length matches
   9248 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{ServerSideEncryption: dstencryption})
   9249 	if err != nil {
   9250 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9251 		return
   9252 	}
   9253 
   9254 	if objInfo.Size != (5*1024*1024)*2+1 {
   9255 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9256 		return
   9257 	}
   9258 
   9259 	// Now we read the data back
   9260 	getOpts := minio.GetObjectOptions{ServerSideEncryption: dstencryption}
   9261 	getOpts.SetRange(0, 5*1024*1024-1)
   9262 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9263 	if err != nil {
   9264 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9265 		return
   9266 	}
   9267 	getBuf := make([]byte, 5*1024*1024)
   9268 	_, err = readFull(r, getBuf)
   9269 	if err != nil {
   9270 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9271 		return
   9272 	}
   9273 	if !bytes.Equal(getBuf, buf) {
   9274 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
   9275 		return
   9276 	}
   9277 
   9278 	getOpts.SetRange(5*1024*1024, 0)
   9279 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9280 	if err != nil {
   9281 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9282 		return
   9283 	}
   9284 	getBuf = make([]byte, 5*1024*1024+1)
   9285 	_, err = readFull(r, getBuf)
   9286 	if err != nil {
   9287 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9288 		return
   9289 	}
   9290 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
   9291 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
   9292 		return
   9293 	}
   9294 	if getBuf[5*1024*1024] != buf[0] {
   9295 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9296 		return
   9297 	}
   9298 
   9299 	successLogger(testName, function, args, startTime).Info()
   9300 
   9301 	// Do not need to remove destBucketName its same as bucketName.
   9302 }
   9303 
   9304 // Test Core CopyObjectPart implementation for SSEC encrypted to unencrypted copy
   9305 func testSSECEncryptedToUnencryptedCopyPart() {
   9306 	// initialize logging params
   9307 	startTime := time.Now()
   9308 	testName := getFuncName()
   9309 	function := "CopyObjectPart(destination, source)"
   9310 	args := map[string]interface{}{}
   9311 
   9312 	// Instantiate new minio client object
   9313 	client, err := minio.New(os.Getenv(serverEndpoint),
   9314 		&minio.Options{
   9315 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   9316 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   9317 		})
   9318 	if err != nil {
   9319 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   9320 		return
   9321 	}
   9322 
   9323 	// Instantiate new core client object.
   9324 	c := minio.Core{client}
   9325 
   9326 	// Enable tracing, write to stderr.
   9327 	// c.TraceOn(os.Stderr)
   9328 
   9329 	// Set user agent.
   9330 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   9331 
   9332 	// Generate a new random bucket name.
   9333 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   9334 
   9335 	// Make a new bucket.
   9336 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   9337 	if err != nil {
   9338 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   9339 		return
   9340 	}
   9341 	defer cleanupBucket(bucketName, client)
   9342 	// Make a buffer with 5MB of data
   9343 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
   9344 
   9345 	// Save the data
   9346 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   9347 	password := "correct horse battery staple"
   9348 	srcencryption := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   9349 
   9350 	opts := minio.PutObjectOptions{
   9351 		UserMetadata: map[string]string{
   9352 			"Content-Type": "binary/octet-stream",
   9353 		},
   9354 		ServerSideEncryption: srcencryption,
   9355 	}
   9356 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
   9357 	if err != nil {
   9358 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   9359 		return
   9360 	}
   9361 
   9362 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcencryption})
   9363 	if err != nil {
   9364 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9365 		return
   9366 	}
   9367 
   9368 	if st.Size != int64(len(buf)) {
   9369 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
   9370 		return
   9371 	}
   9372 
   9373 	destBucketName := bucketName
   9374 	destObjectName := objectName + "-dest"
   9375 	var dstencryption encrypt.ServerSide
   9376 
   9377 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
   9378 	if err != nil {
   9379 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9380 		return
   9381 	}
   9382 
   9383 	// Content of the destination object will be two copies of
   9384 	// `objectName` concatenated, followed by first byte of
   9385 	// `objectName`.
   9386 	metadata := make(map[string]string)
   9387 	header := make(http.Header)
   9388 	encrypt.SSECopy(srcencryption).Marshal(header)
   9389 	for k, v := range header {
   9390 		metadata[k] = v[0]
   9391 	}
   9392 
   9393 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
   9394 
   9395 	// First of three parts
   9396 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9397 	if err != nil {
   9398 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9399 		return
   9400 	}
   9401 
   9402 	// Second of three parts
   9403 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9404 	if err != nil {
   9405 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9406 		return
   9407 	}
   9408 
   9409 	// Last of three parts
   9410 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9411 	if err != nil {
   9412 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9413 		return
   9414 	}
   9415 
   9416 	// Complete the multipart upload
   9417 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9418 	if err != nil {
   9419 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9420 		return
   9421 	}
   9422 
   9423 	// Stat the object and check its length matches
   9424 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
   9425 	if err != nil {
   9426 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9427 		return
   9428 	}
   9429 
   9430 	if objInfo.Size != (5*1024*1024)*2+1 {
   9431 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9432 		return
   9433 	}
   9434 
   9435 	// Now we read the data back
   9436 	getOpts := minio.GetObjectOptions{}
   9437 	getOpts.SetRange(0, 5*1024*1024-1)
   9438 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9439 	if err != nil {
   9440 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9441 		return
   9442 	}
   9443 	getBuf := make([]byte, 5*1024*1024)
   9444 	_, err = readFull(r, getBuf)
   9445 	if err != nil {
   9446 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9447 		return
   9448 	}
   9449 	if !bytes.Equal(getBuf, buf) {
   9450 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
   9451 		return
   9452 	}
   9453 
   9454 	getOpts.SetRange(5*1024*1024, 0)
   9455 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9456 	if err != nil {
   9457 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9458 		return
   9459 	}
   9460 	getBuf = make([]byte, 5*1024*1024+1)
   9461 	_, err = readFull(r, getBuf)
   9462 	if err != nil {
   9463 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9464 		return
   9465 	}
   9466 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
   9467 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
   9468 		return
   9469 	}
   9470 	if getBuf[5*1024*1024] != buf[0] {
   9471 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9472 		return
   9473 	}
   9474 
   9475 	successLogger(testName, function, args, startTime).Info()
   9476 
   9477 	// Do not need to remove destBucketName its same as bucketName.
   9478 }
   9479 
   9480 // Test Core CopyObjectPart implementation for SSEC encrypted to SSE-S3 encrypted copy
   9481 func testSSECEncryptedToSSES3CopyObjectPart() {
   9482 	// initialize logging params
   9483 	startTime := time.Now()
   9484 	testName := getFuncName()
   9485 	function := "CopyObjectPart(destination, source)"
   9486 	args := map[string]interface{}{}
   9487 
   9488 	// Instantiate new minio client object
   9489 	client, err := minio.New(os.Getenv(serverEndpoint),
   9490 		&minio.Options{
   9491 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   9492 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   9493 		})
   9494 	if err != nil {
   9495 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   9496 		return
   9497 	}
   9498 
   9499 	// Instantiate new core client object.
   9500 	c := minio.Core{client}
   9501 
   9502 	// Enable tracing, write to stderr.
   9503 	// c.TraceOn(os.Stderr)
   9504 
   9505 	// Set user agent.
   9506 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   9507 
   9508 	// Generate a new random bucket name.
   9509 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   9510 
   9511 	// Make a new bucket.
   9512 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   9513 	if err != nil {
   9514 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   9515 		return
   9516 	}
   9517 	defer cleanupBucket(bucketName, client)
   9518 	// Make a buffer with 5MB of data
   9519 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
   9520 
   9521 	// Save the data
   9522 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   9523 	password := "correct horse battery staple"
   9524 	srcencryption := encrypt.DefaultPBKDF([]byte(password), []byte(bucketName+objectName))
   9525 	putmetadata := map[string]string{
   9526 		"Content-Type": "binary/octet-stream",
   9527 	}
   9528 	opts := minio.PutObjectOptions{
   9529 		UserMetadata:         putmetadata,
   9530 		ServerSideEncryption: srcencryption,
   9531 	}
   9532 
   9533 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
   9534 	if err != nil {
   9535 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   9536 		return
   9537 	}
   9538 
   9539 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcencryption})
   9540 	if err != nil {
   9541 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9542 		return
   9543 	}
   9544 
   9545 	if st.Size != int64(len(buf)) {
   9546 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
   9547 		return
   9548 	}
   9549 
   9550 	destBucketName := bucketName
   9551 	destObjectName := objectName + "-dest"
   9552 	dstencryption := encrypt.NewSSE()
   9553 
   9554 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
   9555 	if err != nil {
   9556 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9557 		return
   9558 	}
   9559 
   9560 	// Content of the destination object will be two copies of
   9561 	// `objectName` concatenated, followed by first byte of
   9562 	// `objectName`.
   9563 	metadata := make(map[string]string)
   9564 	header := make(http.Header)
   9565 	encrypt.SSECopy(srcencryption).Marshal(header)
   9566 	dstencryption.Marshal(header)
   9567 
   9568 	for k, v := range header {
   9569 		metadata[k] = v[0]
   9570 	}
   9571 
   9572 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
   9573 
   9574 	// First of three parts
   9575 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9576 	if err != nil {
   9577 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9578 		return
   9579 	}
   9580 
   9581 	// Second of three parts
   9582 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9583 	if err != nil {
   9584 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9585 		return
   9586 	}
   9587 
   9588 	// Last of three parts
   9589 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9590 	if err != nil {
   9591 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9592 		return
   9593 	}
   9594 
   9595 	// Complete the multipart upload
   9596 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9597 	if err != nil {
   9598 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9599 		return
   9600 	}
   9601 
   9602 	// Stat the object and check its length matches
   9603 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
   9604 	if err != nil {
   9605 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9606 		return
   9607 	}
   9608 
   9609 	if objInfo.Size != (5*1024*1024)*2+1 {
   9610 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9611 		return
   9612 	}
   9613 
   9614 	// Now we read the data back
   9615 	getOpts := minio.GetObjectOptions{}
   9616 	getOpts.SetRange(0, 5*1024*1024-1)
   9617 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9618 	if err != nil {
   9619 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9620 		return
   9621 	}
   9622 	getBuf := make([]byte, 5*1024*1024)
   9623 	_, err = readFull(r, getBuf)
   9624 	if err != nil {
   9625 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9626 		return
   9627 	}
   9628 	if !bytes.Equal(getBuf, buf) {
   9629 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
   9630 		return
   9631 	}
   9632 
   9633 	getOpts.SetRange(5*1024*1024, 0)
   9634 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9635 	if err != nil {
   9636 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9637 		return
   9638 	}
   9639 	getBuf = make([]byte, 5*1024*1024+1)
   9640 	_, err = readFull(r, getBuf)
   9641 	if err != nil {
   9642 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9643 		return
   9644 	}
   9645 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
   9646 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
   9647 		return
   9648 	}
   9649 	if getBuf[5*1024*1024] != buf[0] {
   9650 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9651 		return
   9652 	}
   9653 
   9654 	successLogger(testName, function, args, startTime).Info()
   9655 
   9656 	// Do not need to remove destBucketName its same as bucketName.
   9657 }
   9658 
   9659 // Test Core CopyObjectPart implementation for unencrypted to SSEC encryption copy part
   9660 func testUnencryptedToSSECCopyObjectPart() {
   9661 	// initialize logging params
   9662 	startTime := time.Now()
   9663 	testName := getFuncName()
   9664 	function := "CopyObjectPart(destination, source)"
   9665 	args := map[string]interface{}{}
   9666 
   9667 	// Instantiate new minio client object
   9668 	client, err := minio.New(os.Getenv(serverEndpoint),
   9669 		&minio.Options{
   9670 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   9671 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   9672 		})
   9673 	if err != nil {
   9674 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   9675 		return
   9676 	}
   9677 
   9678 	// Instantiate new core client object.
   9679 	c := minio.Core{client}
   9680 
   9681 	// Enable tracing, write to stderr.
   9682 	// c.TraceOn(os.Stderr)
   9683 
   9684 	// Set user agent.
   9685 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   9686 
   9687 	// Generate a new random bucket name.
   9688 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   9689 
   9690 	// Make a new bucket.
   9691 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   9692 	if err != nil {
   9693 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   9694 		return
   9695 	}
   9696 	defer cleanupBucket(bucketName, client)
   9697 	// Make a buffer with 5MB of data
   9698 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
   9699 
   9700 	// Save the data
   9701 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   9702 	password := "correct horse battery staple"
   9703 	putmetadata := map[string]string{
   9704 		"Content-Type": "binary/octet-stream",
   9705 	}
   9706 	opts := minio.PutObjectOptions{
   9707 		UserMetadata: putmetadata,
   9708 	}
   9709 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
   9710 	if err != nil {
   9711 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   9712 		return
   9713 	}
   9714 
   9715 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
   9716 	if err != nil {
   9717 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9718 		return
   9719 	}
   9720 
   9721 	if st.Size != int64(len(buf)) {
   9722 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
   9723 		return
   9724 	}
   9725 
   9726 	destBucketName := bucketName
   9727 	destObjectName := objectName + "-dest"
   9728 	dstencryption := encrypt.DefaultPBKDF([]byte(password), []byte(destBucketName+destObjectName))
   9729 
   9730 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
   9731 	if err != nil {
   9732 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9733 		return
   9734 	}
   9735 
   9736 	// Content of the destination object will be two copies of
   9737 	// `objectName` concatenated, followed by first byte of
   9738 	// `objectName`.
   9739 	metadata := make(map[string]string)
   9740 	header := make(http.Header)
   9741 	dstencryption.Marshal(header)
   9742 	for k, v := range header {
   9743 		metadata[k] = v[0]
   9744 	}
   9745 
   9746 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
   9747 
   9748 	// First of three parts
   9749 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9750 	if err != nil {
   9751 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9752 		return
   9753 	}
   9754 
   9755 	// Second of three parts
   9756 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9757 	if err != nil {
   9758 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9759 		return
   9760 	}
   9761 
   9762 	// Last of three parts
   9763 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9764 	if err != nil {
   9765 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9766 		return
   9767 	}
   9768 
   9769 	// Complete the multipart upload
   9770 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9771 	if err != nil {
   9772 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9773 		return
   9774 	}
   9775 
   9776 	// Stat the object and check its length matches
   9777 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{ServerSideEncryption: dstencryption})
   9778 	if err != nil {
   9779 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9780 		return
   9781 	}
   9782 
   9783 	if objInfo.Size != (5*1024*1024)*2+1 {
   9784 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9785 		return
   9786 	}
   9787 
   9788 	// Now we read the data back
   9789 	getOpts := minio.GetObjectOptions{ServerSideEncryption: dstencryption}
   9790 	getOpts.SetRange(0, 5*1024*1024-1)
   9791 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9792 	if err != nil {
   9793 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9794 		return
   9795 	}
   9796 	getBuf := make([]byte, 5*1024*1024)
   9797 	_, err = readFull(r, getBuf)
   9798 	if err != nil {
   9799 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9800 		return
   9801 	}
   9802 	if !bytes.Equal(getBuf, buf) {
   9803 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
   9804 		return
   9805 	}
   9806 
   9807 	getOpts.SetRange(5*1024*1024, 0)
   9808 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9809 	if err != nil {
   9810 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9811 		return
   9812 	}
   9813 	getBuf = make([]byte, 5*1024*1024+1)
   9814 	_, err = readFull(r, getBuf)
   9815 	if err != nil {
   9816 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9817 		return
   9818 	}
   9819 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
   9820 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
   9821 		return
   9822 	}
   9823 	if getBuf[5*1024*1024] != buf[0] {
   9824 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9825 		return
   9826 	}
   9827 
   9828 	successLogger(testName, function, args, startTime).Info()
   9829 
   9830 	// Do not need to remove destBucketName its same as bucketName.
   9831 }
   9832 
   9833 // Test Core CopyObjectPart implementation for unencrypted to unencrypted copy
   9834 func testUnencryptedToUnencryptedCopyPart() {
   9835 	// initialize logging params
   9836 	startTime := time.Now()
   9837 	testName := getFuncName()
   9838 	function := "CopyObjectPart(destination, source)"
   9839 	args := map[string]interface{}{}
   9840 
   9841 	// Instantiate new minio client object
   9842 	client, err := minio.New(os.Getenv(serverEndpoint),
   9843 		&minio.Options{
   9844 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
   9845 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
   9846 		})
   9847 	if err != nil {
   9848 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
   9849 		return
   9850 	}
   9851 
   9852 	// Instantiate new core client object.
   9853 	c := minio.Core{client}
   9854 
   9855 	// Enable tracing, write to stderr.
   9856 	// c.TraceOn(os.Stderr)
   9857 
   9858 	// Set user agent.
   9859 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
   9860 
   9861 	// Generate a new random bucket name.
   9862 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
   9863 
   9864 	// Make a new bucket.
   9865 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
   9866 	if err != nil {
   9867 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
   9868 		return
   9869 	}
   9870 	defer cleanupBucket(bucketName, client)
   9871 	// Make a buffer with 5MB of data
   9872 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
   9873 
   9874 	// Save the data
   9875 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
   9876 	putmetadata := map[string]string{
   9877 		"Content-Type": "binary/octet-stream",
   9878 	}
   9879 	opts := minio.PutObjectOptions{
   9880 		UserMetadata: putmetadata,
   9881 	}
   9882 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
   9883 	if err != nil {
   9884 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
   9885 		return
   9886 	}
   9887 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
   9888 	if err != nil {
   9889 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9890 		return
   9891 	}
   9892 
   9893 	if st.Size != int64(len(buf)) {
   9894 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
   9895 		return
   9896 	}
   9897 
   9898 	destBucketName := bucketName
   9899 	destObjectName := objectName + "-dest"
   9900 
   9901 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{})
   9902 	if err != nil {
   9903 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
   9904 		return
   9905 	}
   9906 
   9907 	// Content of the destination object will be two copies of
   9908 	// `objectName` concatenated, followed by first byte of
   9909 	// `objectName`.
   9910 	metadata := make(map[string]string)
   9911 	header := make(http.Header)
   9912 	for k, v := range header {
   9913 		metadata[k] = v[0]
   9914 	}
   9915 
   9916 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
   9917 
   9918 	// First of three parts
   9919 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
   9920 	if err != nil {
   9921 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9922 		return
   9923 	}
   9924 
   9925 	// Second of three parts
   9926 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
   9927 	if err != nil {
   9928 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9929 		return
   9930 	}
   9931 
   9932 	// Last of three parts
   9933 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
   9934 	if err != nil {
   9935 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
   9936 		return
   9937 	}
   9938 
   9939 	// Complete the multipart upload
   9940 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
   9941 	if err != nil {
   9942 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
   9943 		return
   9944 	}
   9945 
   9946 	// Stat the object and check its length matches
   9947 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
   9948 	if err != nil {
   9949 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
   9950 		return
   9951 	}
   9952 
   9953 	if objInfo.Size != (5*1024*1024)*2+1 {
   9954 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
   9955 		return
   9956 	}
   9957 
   9958 	// Now we read the data back
   9959 	getOpts := minio.GetObjectOptions{}
   9960 	getOpts.SetRange(0, 5*1024*1024-1)
   9961 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9962 	if err != nil {
   9963 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9964 		return
   9965 	}
   9966 	getBuf := make([]byte, 5*1024*1024)
   9967 	_, err = readFull(r, getBuf)
   9968 	if err != nil {
   9969 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9970 		return
   9971 	}
   9972 	if !bytes.Equal(getBuf, buf) {
   9973 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
   9974 		return
   9975 	}
   9976 
   9977 	getOpts.SetRange(5*1024*1024, 0)
   9978 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
   9979 	if err != nil {
   9980 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
   9981 		return
   9982 	}
   9983 	getBuf = make([]byte, 5*1024*1024+1)
   9984 	_, err = readFull(r, getBuf)
   9985 	if err != nil {
   9986 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
   9987 		return
   9988 	}
   9989 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
   9990 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
   9991 		return
   9992 	}
   9993 	if getBuf[5*1024*1024] != buf[0] {
   9994 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
   9995 		return
   9996 	}
   9997 
   9998 	successLogger(testName, function, args, startTime).Info()
   9999 
  10000 	// Do not need to remove destBucketName its same as bucketName.
  10001 }
  10002 
  10003 // Test Core CopyObjectPart implementation for unencrypted to SSE-S3 encrypted copy
  10004 func testUnencryptedToSSES3CopyObjectPart() {
  10005 	// initialize logging params
  10006 	startTime := time.Now()
  10007 	testName := getFuncName()
  10008 	function := "CopyObjectPart(destination, source)"
  10009 	args := map[string]interface{}{}
  10010 
  10011 	// Instantiate new minio client object
  10012 	client, err := minio.New(os.Getenv(serverEndpoint),
  10013 		&minio.Options{
  10014 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10015 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10016 		})
  10017 	if err != nil {
  10018 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10019 		return
  10020 	}
  10021 
  10022 	// Instantiate new core client object.
  10023 	c := minio.Core{client}
  10024 
  10025 	// Enable tracing, write to stderr.
  10026 	// c.TraceOn(os.Stderr)
  10027 
  10028 	// Set user agent.
  10029 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  10030 
  10031 	// Generate a new random bucket name.
  10032 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  10033 
  10034 	// Make a new bucket.
  10035 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10036 	if err != nil {
  10037 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10038 		return
  10039 	}
  10040 	defer cleanupBucket(bucketName, client)
  10041 	// Make a buffer with 5MB of data
  10042 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
  10043 
  10044 	// Save the data
  10045 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  10046 	opts := minio.PutObjectOptions{
  10047 		UserMetadata: map[string]string{
  10048 			"Content-Type": "binary/octet-stream",
  10049 		},
  10050 	}
  10051 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
  10052 	if err != nil {
  10053 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  10054 		return
  10055 	}
  10056 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
  10057 	if err != nil {
  10058 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10059 		return
  10060 	}
  10061 
  10062 	if st.Size != int64(len(buf)) {
  10063 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
  10064 		return
  10065 	}
  10066 
  10067 	destBucketName := bucketName
  10068 	destObjectName := objectName + "-dest"
  10069 	dstencryption := encrypt.NewSSE()
  10070 
  10071 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
  10072 	if err != nil {
  10073 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
  10074 		return
  10075 	}
  10076 
  10077 	// Content of the destination object will be two copies of
  10078 	// `objectName` concatenated, followed by first byte of
  10079 	// `objectName`.
  10080 	metadata := make(map[string]string)
  10081 	header := make(http.Header)
  10082 	dstencryption.Marshal(header)
  10083 
  10084 	for k, v := range header {
  10085 		metadata[k] = v[0]
  10086 	}
  10087 
  10088 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
  10089 
  10090 	// First of three parts
  10091 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
  10092 	if err != nil {
  10093 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10094 		return
  10095 	}
  10096 
  10097 	// Second of three parts
  10098 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
  10099 	if err != nil {
  10100 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10101 		return
  10102 	}
  10103 
  10104 	// Last of three parts
  10105 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
  10106 	if err != nil {
  10107 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10108 		return
  10109 	}
  10110 
  10111 	// Complete the multipart upload
  10112 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
  10113 	if err != nil {
  10114 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
  10115 		return
  10116 	}
  10117 
  10118 	// Stat the object and check its length matches
  10119 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
  10120 	if err != nil {
  10121 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10122 		return
  10123 	}
  10124 
  10125 	if objInfo.Size != (5*1024*1024)*2+1 {
  10126 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
  10127 		return
  10128 	}
  10129 
  10130 	// Now we read the data back
  10131 	getOpts := minio.GetObjectOptions{}
  10132 	getOpts.SetRange(0, 5*1024*1024-1)
  10133 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10134 	if err != nil {
  10135 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10136 		return
  10137 	}
  10138 	getBuf := make([]byte, 5*1024*1024)
  10139 	_, err = readFull(r, getBuf)
  10140 	if err != nil {
  10141 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10142 		return
  10143 	}
  10144 	if !bytes.Equal(getBuf, buf) {
  10145 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
  10146 		return
  10147 	}
  10148 
  10149 	getOpts.SetRange(5*1024*1024, 0)
  10150 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10151 	if err != nil {
  10152 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10153 		return
  10154 	}
  10155 	getBuf = make([]byte, 5*1024*1024+1)
  10156 	_, err = readFull(r, getBuf)
  10157 	if err != nil {
  10158 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10159 		return
  10160 	}
  10161 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
  10162 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
  10163 		return
  10164 	}
  10165 	if getBuf[5*1024*1024] != buf[0] {
  10166 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
  10167 		return
  10168 	}
  10169 
  10170 	successLogger(testName, function, args, startTime).Info()
  10171 
  10172 	// Do not need to remove destBucketName its same as bucketName.
  10173 }
  10174 
  10175 // Test Core CopyObjectPart implementation for SSE-S3 to SSEC encryption copy part
  10176 func testSSES3EncryptedToSSECCopyObjectPart() {
  10177 	// initialize logging params
  10178 	startTime := time.Now()
  10179 	testName := getFuncName()
  10180 	function := "CopyObjectPart(destination, source)"
  10181 	args := map[string]interface{}{}
  10182 
  10183 	// Instantiate new minio client object
  10184 	client, err := minio.New(os.Getenv(serverEndpoint),
  10185 		&minio.Options{
  10186 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10187 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10188 		})
  10189 	if err != nil {
  10190 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10191 		return
  10192 	}
  10193 
  10194 	// Instantiate new core client object.
  10195 	c := minio.Core{client}
  10196 
  10197 	// Enable tracing, write to stderr.
  10198 	// c.TraceOn(os.Stderr)
  10199 
  10200 	// Set user agent.
  10201 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  10202 
  10203 	// Generate a new random bucket name.
  10204 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  10205 
  10206 	// Make a new bucket.
  10207 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10208 	if err != nil {
  10209 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10210 		return
  10211 	}
  10212 	defer cleanupBucket(bucketName, client)
  10213 	// Make a buffer with 5MB of data
  10214 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
  10215 
  10216 	// Save the data
  10217 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  10218 	password := "correct horse battery staple"
  10219 	srcEncryption := encrypt.NewSSE()
  10220 	opts := minio.PutObjectOptions{
  10221 		UserMetadata: map[string]string{
  10222 			"Content-Type": "binary/octet-stream",
  10223 		},
  10224 		ServerSideEncryption: srcEncryption,
  10225 	}
  10226 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
  10227 	if err != nil {
  10228 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  10229 		return
  10230 	}
  10231 
  10232 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcEncryption})
  10233 	if err != nil {
  10234 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10235 		return
  10236 	}
  10237 
  10238 	if st.Size != int64(len(buf)) {
  10239 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
  10240 		return
  10241 	}
  10242 
  10243 	destBucketName := bucketName
  10244 	destObjectName := objectName + "-dest"
  10245 	dstencryption := encrypt.DefaultPBKDF([]byte(password), []byte(destBucketName+destObjectName))
  10246 
  10247 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
  10248 	if err != nil {
  10249 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
  10250 		return
  10251 	}
  10252 
  10253 	// Content of the destination object will be two copies of
  10254 	// `objectName` concatenated, followed by first byte of
  10255 	// `objectName`.
  10256 	metadata := make(map[string]string)
  10257 	header := make(http.Header)
  10258 	dstencryption.Marshal(header)
  10259 	for k, v := range header {
  10260 		metadata[k] = v[0]
  10261 	}
  10262 
  10263 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
  10264 
  10265 	// First of three parts
  10266 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
  10267 	if err != nil {
  10268 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10269 		return
  10270 	}
  10271 
  10272 	// Second of three parts
  10273 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
  10274 	if err != nil {
  10275 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10276 		return
  10277 	}
  10278 
  10279 	// Last of three parts
  10280 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
  10281 	if err != nil {
  10282 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10283 		return
  10284 	}
  10285 
  10286 	// Complete the multipart upload
  10287 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
  10288 	if err != nil {
  10289 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
  10290 		return
  10291 	}
  10292 
  10293 	// Stat the object and check its length matches
  10294 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{ServerSideEncryption: dstencryption})
  10295 	if err != nil {
  10296 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10297 		return
  10298 	}
  10299 
  10300 	if objInfo.Size != (5*1024*1024)*2+1 {
  10301 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
  10302 		return
  10303 	}
  10304 
  10305 	// Now we read the data back
  10306 	getOpts := minio.GetObjectOptions{ServerSideEncryption: dstencryption}
  10307 	getOpts.SetRange(0, 5*1024*1024-1)
  10308 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10309 	if err != nil {
  10310 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10311 		return
  10312 	}
  10313 	getBuf := make([]byte, 5*1024*1024)
  10314 	_, err = readFull(r, getBuf)
  10315 	if err != nil {
  10316 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10317 		return
  10318 	}
  10319 	if !bytes.Equal(getBuf, buf) {
  10320 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
  10321 		return
  10322 	}
  10323 
  10324 	getOpts.SetRange(5*1024*1024, 0)
  10325 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10326 	if err != nil {
  10327 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10328 		return
  10329 	}
  10330 	getBuf = make([]byte, 5*1024*1024+1)
  10331 	_, err = readFull(r, getBuf)
  10332 	if err != nil {
  10333 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10334 		return
  10335 	}
  10336 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
  10337 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
  10338 		return
  10339 	}
  10340 	if getBuf[5*1024*1024] != buf[0] {
  10341 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
  10342 		return
  10343 	}
  10344 
  10345 	successLogger(testName, function, args, startTime).Info()
  10346 
  10347 	// Do not need to remove destBucketName its same as bucketName.
  10348 }
  10349 
  10350 // Test Core CopyObjectPart implementation for unencrypted to unencrypted copy
  10351 func testSSES3EncryptedToUnencryptedCopyPart() {
  10352 	// initialize logging params
  10353 	startTime := time.Now()
  10354 	testName := getFuncName()
  10355 	function := "CopyObjectPart(destination, source)"
  10356 	args := map[string]interface{}{}
  10357 
  10358 	// Instantiate new minio client object
  10359 	client, err := minio.New(os.Getenv(serverEndpoint),
  10360 		&minio.Options{
  10361 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10362 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10363 		})
  10364 	if err != nil {
  10365 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10366 		return
  10367 	}
  10368 
  10369 	// Instantiate new core client object.
  10370 	c := minio.Core{client}
  10371 
  10372 	// Enable tracing, write to stderr.
  10373 	// c.TraceOn(os.Stderr)
  10374 
  10375 	// Set user agent.
  10376 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  10377 
  10378 	// Generate a new random bucket name.
  10379 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  10380 
  10381 	// Make a new bucket.
  10382 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10383 	if err != nil {
  10384 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10385 		return
  10386 	}
  10387 	defer cleanupBucket(bucketName, client)
  10388 	// Make a buffer with 5MB of data
  10389 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
  10390 
  10391 	// Save the data
  10392 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  10393 	srcEncryption := encrypt.NewSSE()
  10394 	opts := minio.PutObjectOptions{
  10395 		UserMetadata: map[string]string{
  10396 			"Content-Type": "binary/octet-stream",
  10397 		},
  10398 		ServerSideEncryption: srcEncryption,
  10399 	}
  10400 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
  10401 	if err != nil {
  10402 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  10403 		return
  10404 	}
  10405 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcEncryption})
  10406 	if err != nil {
  10407 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10408 		return
  10409 	}
  10410 
  10411 	if st.Size != int64(len(buf)) {
  10412 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
  10413 		return
  10414 	}
  10415 
  10416 	destBucketName := bucketName
  10417 	destObjectName := objectName + "-dest"
  10418 
  10419 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{})
  10420 	if err != nil {
  10421 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
  10422 		return
  10423 	}
  10424 
  10425 	// Content of the destination object will be two copies of
  10426 	// `objectName` concatenated, followed by first byte of
  10427 	// `objectName`.
  10428 	metadata := make(map[string]string)
  10429 	header := make(http.Header)
  10430 	for k, v := range header {
  10431 		metadata[k] = v[0]
  10432 	}
  10433 
  10434 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
  10435 
  10436 	// First of three parts
  10437 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
  10438 	if err != nil {
  10439 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10440 		return
  10441 	}
  10442 
  10443 	// Second of three parts
  10444 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
  10445 	if err != nil {
  10446 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10447 		return
  10448 	}
  10449 
  10450 	// Last of three parts
  10451 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
  10452 	if err != nil {
  10453 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10454 		return
  10455 	}
  10456 
  10457 	// Complete the multipart upload
  10458 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
  10459 	if err != nil {
  10460 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
  10461 		return
  10462 	}
  10463 
  10464 	// Stat the object and check its length matches
  10465 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
  10466 	if err != nil {
  10467 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10468 		return
  10469 	}
  10470 
  10471 	if objInfo.Size != (5*1024*1024)*2+1 {
  10472 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
  10473 		return
  10474 	}
  10475 
  10476 	// Now we read the data back
  10477 	getOpts := minio.GetObjectOptions{}
  10478 	getOpts.SetRange(0, 5*1024*1024-1)
  10479 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10480 	if err != nil {
  10481 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10482 		return
  10483 	}
  10484 	getBuf := make([]byte, 5*1024*1024)
  10485 	_, err = readFull(r, getBuf)
  10486 	if err != nil {
  10487 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10488 		return
  10489 	}
  10490 	if !bytes.Equal(getBuf, buf) {
  10491 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
  10492 		return
  10493 	}
  10494 
  10495 	getOpts.SetRange(5*1024*1024, 0)
  10496 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10497 	if err != nil {
  10498 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10499 		return
  10500 	}
  10501 	getBuf = make([]byte, 5*1024*1024+1)
  10502 	_, err = readFull(r, getBuf)
  10503 	if err != nil {
  10504 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10505 		return
  10506 	}
  10507 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
  10508 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
  10509 		return
  10510 	}
  10511 	if getBuf[5*1024*1024] != buf[0] {
  10512 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
  10513 		return
  10514 	}
  10515 
  10516 	successLogger(testName, function, args, startTime).Info()
  10517 
  10518 	// Do not need to remove destBucketName its same as bucketName.
  10519 }
  10520 
  10521 // Test Core CopyObjectPart implementation for unencrypted to SSE-S3 encrypted copy
  10522 func testSSES3EncryptedToSSES3CopyObjectPart() {
  10523 	// initialize logging params
  10524 	startTime := time.Now()
  10525 	testName := getFuncName()
  10526 	function := "CopyObjectPart(destination, source)"
  10527 	args := map[string]interface{}{}
  10528 
  10529 	// Instantiate new minio client object
  10530 	client, err := minio.New(os.Getenv(serverEndpoint),
  10531 		&minio.Options{
  10532 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10533 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10534 		})
  10535 	if err != nil {
  10536 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10537 		return
  10538 	}
  10539 
  10540 	// Instantiate new core client object.
  10541 	c := minio.Core{client}
  10542 
  10543 	// Enable tracing, write to stderr.
  10544 	// c.TraceOn(os.Stderr)
  10545 
  10546 	// Set user agent.
  10547 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  10548 
  10549 	// Generate a new random bucket name.
  10550 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  10551 
  10552 	// Make a new bucket.
  10553 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10554 	if err != nil {
  10555 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10556 		return
  10557 	}
  10558 	defer cleanupBucket(bucketName, client)
  10559 	// Make a buffer with 5MB of data
  10560 	buf := bytes.Repeat([]byte("abcde"), 1024*1024)
  10561 
  10562 	// Save the data
  10563 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  10564 	srcEncryption := encrypt.NewSSE()
  10565 	opts := minio.PutObjectOptions{
  10566 		UserMetadata: map[string]string{
  10567 			"Content-Type": "binary/octet-stream",
  10568 		},
  10569 		ServerSideEncryption: srcEncryption,
  10570 	}
  10571 
  10572 	uploadInfo, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), "", "", opts)
  10573 	if err != nil {
  10574 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  10575 		return
  10576 	}
  10577 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{ServerSideEncryption: srcEncryption})
  10578 	if err != nil {
  10579 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10580 		return
  10581 	}
  10582 	if st.Size != int64(len(buf)) {
  10583 		logError(testName, function, args, startTime, "", fmt.Sprintf("Error: number of bytes does not match, want %v, got %v\n", len(buf), st.Size), err)
  10584 		return
  10585 	}
  10586 
  10587 	destBucketName := bucketName
  10588 	destObjectName := objectName + "-dest"
  10589 	dstencryption := encrypt.NewSSE()
  10590 
  10591 	uploadID, err := c.NewMultipartUpload(context.Background(), destBucketName, destObjectName, minio.PutObjectOptions{ServerSideEncryption: dstencryption})
  10592 	if err != nil {
  10593 		logError(testName, function, args, startTime, "", "NewMultipartUpload call failed", err)
  10594 		return
  10595 	}
  10596 
  10597 	// Content of the destination object will be two copies of
  10598 	// `objectName` concatenated, followed by first byte of
  10599 	// `objectName`.
  10600 	metadata := make(map[string]string)
  10601 	header := make(http.Header)
  10602 	dstencryption.Marshal(header)
  10603 
  10604 	for k, v := range header {
  10605 		metadata[k] = v[0]
  10606 	}
  10607 
  10608 	metadata["x-amz-copy-source-if-match"] = uploadInfo.ETag
  10609 
  10610 	// First of three parts
  10611 	fstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 1, 0, -1, metadata)
  10612 	if err != nil {
  10613 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10614 		return
  10615 	}
  10616 
  10617 	// Second of three parts
  10618 	sndPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 2, 0, -1, metadata)
  10619 	if err != nil {
  10620 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10621 		return
  10622 	}
  10623 
  10624 	// Last of three parts
  10625 	lstPart, err := c.CopyObjectPart(context.Background(), bucketName, objectName, destBucketName, destObjectName, uploadID, 3, 0, 1, metadata)
  10626 	if err != nil {
  10627 		logError(testName, function, args, startTime, "", "CopyObjectPart call failed", err)
  10628 		return
  10629 	}
  10630 
  10631 	// Complete the multipart upload
  10632 	_, err = c.CompleteMultipartUpload(context.Background(), destBucketName, destObjectName, uploadID, []minio.CompletePart{fstPart, sndPart, lstPart}, minio.PutObjectOptions{})
  10633 	if err != nil {
  10634 		logError(testName, function, args, startTime, "", "CompleteMultipartUpload call failed", err)
  10635 		return
  10636 	}
  10637 
  10638 	// Stat the object and check its length matches
  10639 	objInfo, err := c.StatObject(context.Background(), destBucketName, destObjectName, minio.StatObjectOptions{})
  10640 	if err != nil {
  10641 		logError(testName, function, args, startTime, "", "StatObject call failed", err)
  10642 		return
  10643 	}
  10644 
  10645 	if objInfo.Size != (5*1024*1024)*2+1 {
  10646 		logError(testName, function, args, startTime, "", "Destination object has incorrect size!", err)
  10647 		return
  10648 	}
  10649 
  10650 	// Now we read the data back
  10651 	getOpts := minio.GetObjectOptions{}
  10652 	getOpts.SetRange(0, 5*1024*1024-1)
  10653 	r, _, _, err := c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10654 	if err != nil {
  10655 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10656 		return
  10657 	}
  10658 	getBuf := make([]byte, 5*1024*1024)
  10659 	_, err = readFull(r, getBuf)
  10660 	if err != nil {
  10661 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10662 		return
  10663 	}
  10664 	if !bytes.Equal(getBuf, buf) {
  10665 		logError(testName, function, args, startTime, "", "Got unexpected data in first 5MB", err)
  10666 		return
  10667 	}
  10668 
  10669 	getOpts.SetRange(5*1024*1024, 0)
  10670 	r, _, _, err = c.GetObject(context.Background(), destBucketName, destObjectName, getOpts)
  10671 	if err != nil {
  10672 		logError(testName, function, args, startTime, "", "GetObject call failed", err)
  10673 		return
  10674 	}
  10675 	getBuf = make([]byte, 5*1024*1024+1)
  10676 	_, err = readFull(r, getBuf)
  10677 	if err != nil {
  10678 		logError(testName, function, args, startTime, "", "Read buffer failed", err)
  10679 		return
  10680 	}
  10681 	if !bytes.Equal(getBuf[:5*1024*1024], buf) {
  10682 		logError(testName, function, args, startTime, "", "Got unexpected data in second 5MB", err)
  10683 		return
  10684 	}
  10685 	if getBuf[5*1024*1024] != buf[0] {
  10686 		logError(testName, function, args, startTime, "", "Got unexpected data in last byte of copied object!", err)
  10687 		return
  10688 	}
  10689 
  10690 	successLogger(testName, function, args, startTime).Info()
  10691 
  10692 	// Do not need to remove destBucketName its same as bucketName.
  10693 }
  10694 
  10695 func testUserMetadataCopying() {
  10696 	// initialize logging params
  10697 	startTime := time.Now()
  10698 	testName := getFuncName()
  10699 	function := "CopyObject(destination, source)"
  10700 	args := map[string]interface{}{}
  10701 
  10702 	// Instantiate new minio client object
  10703 	c, err := minio.New(os.Getenv(serverEndpoint),
  10704 		&minio.Options{
  10705 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10706 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10707 		})
  10708 	if err != nil {
  10709 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
  10710 		return
  10711 	}
  10712 
  10713 	// c.TraceOn(os.Stderr)
  10714 	testUserMetadataCopyingWrapper(c)
  10715 }
  10716 
  10717 func testUserMetadataCopyingWrapper(c *minio.Client) {
  10718 	// initialize logging params
  10719 	startTime := time.Now()
  10720 	testName := getFuncName()
  10721 	function := "CopyObject(destination, source)"
  10722 	args := map[string]interface{}{}
  10723 
  10724 	// Generate a new random bucket name.
  10725 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  10726 	// Make a new bucket in 'us-east-1' (source bucket).
  10727 	err := c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10728 	if err != nil {
  10729 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10730 		return
  10731 	}
  10732 
  10733 	defer cleanupBucket(bucketName, c)
  10734 
  10735 	fetchMeta := func(object string) (h http.Header) {
  10736 		objInfo, err := c.StatObject(context.Background(), bucketName, object, minio.StatObjectOptions{})
  10737 		if err != nil {
  10738 			logError(testName, function, args, startTime, "", "Stat failed", err)
  10739 			return
  10740 		}
  10741 		h = make(http.Header)
  10742 		for k, vs := range objInfo.Metadata {
  10743 			if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
  10744 				h.Add(k, vs[0])
  10745 			}
  10746 		}
  10747 		return h
  10748 	}
  10749 
  10750 	// 1. create a client encrypted object to copy by uploading
  10751 	const srcSize = 1024 * 1024
  10752 	buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 5MiB
  10753 	metadata := make(http.Header)
  10754 	metadata.Set("x-amz-meta-myheader", "myvalue")
  10755 	m := make(map[string]string)
  10756 	m["x-amz-meta-myheader"] = "myvalue"
  10757 	_, err = c.PutObject(context.Background(), bucketName, "srcObject",
  10758 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{UserMetadata: m})
  10759 	if err != nil {
  10760 		logError(testName, function, args, startTime, "", "PutObjectWithMetadata failed", err)
  10761 		return
  10762 	}
  10763 	if !reflect.DeepEqual(metadata, fetchMeta("srcObject")) {
  10764 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10765 		return
  10766 	}
  10767 
  10768 	// 2. create source
  10769 	src := minio.CopySrcOptions{
  10770 		Bucket: bucketName,
  10771 		Object: "srcObject",
  10772 	}
  10773 
  10774 	// 2.1 create destination with metadata set
  10775 	dst1 := minio.CopyDestOptions{
  10776 		Bucket:          bucketName,
  10777 		Object:          "dstObject-1",
  10778 		UserMetadata:    map[string]string{"notmyheader": "notmyvalue"},
  10779 		ReplaceMetadata: true,
  10780 	}
  10781 
  10782 	// 3. Check that copying to an object with metadata set resets
  10783 	// the headers on the copy.
  10784 	args["source"] = src
  10785 	args["destination"] = dst1
  10786 	_, err = c.CopyObject(context.Background(), dst1, src)
  10787 	if err != nil {
  10788 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
  10789 		return
  10790 	}
  10791 
  10792 	expectedHeaders := make(http.Header)
  10793 	expectedHeaders.Set("x-amz-meta-notmyheader", "notmyvalue")
  10794 	if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-1")) {
  10795 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10796 		return
  10797 	}
  10798 
  10799 	// 4. create destination with no metadata set and same source
  10800 	dst2 := minio.CopyDestOptions{
  10801 		Bucket: bucketName,
  10802 		Object: "dstObject-2",
  10803 	}
  10804 
  10805 	// 5. Check that copying to an object with no metadata set,
  10806 	// copies metadata.
  10807 	args["source"] = src
  10808 	args["destination"] = dst2
  10809 	_, err = c.CopyObject(context.Background(), dst2, src)
  10810 	if err != nil {
  10811 		logError(testName, function, args, startTime, "", "CopyObject failed", err)
  10812 		return
  10813 	}
  10814 
  10815 	expectedHeaders = metadata
  10816 	if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-2")) {
  10817 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10818 		return
  10819 	}
  10820 
  10821 	// 6. Compose a pair of sources.
  10822 	dst3 := minio.CopyDestOptions{
  10823 		Bucket:          bucketName,
  10824 		Object:          "dstObject-3",
  10825 		ReplaceMetadata: true,
  10826 	}
  10827 
  10828 	function = "ComposeObject(destination, sources)"
  10829 	args["source"] = []minio.CopySrcOptions{src, src}
  10830 	args["destination"] = dst3
  10831 	_, err = c.ComposeObject(context.Background(), dst3, src, src)
  10832 	if err != nil {
  10833 		logError(testName, function, args, startTime, "", "ComposeObject failed", err)
  10834 		return
  10835 	}
  10836 
  10837 	// Check that no headers are copied in this case
  10838 	if !reflect.DeepEqual(make(http.Header), fetchMeta("dstObject-3")) {
  10839 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10840 		return
  10841 	}
  10842 
  10843 	// 7. Compose a pair of sources with dest user metadata set.
  10844 	dst4 := minio.CopyDestOptions{
  10845 		Bucket:          bucketName,
  10846 		Object:          "dstObject-4",
  10847 		UserMetadata:    map[string]string{"notmyheader": "notmyvalue"},
  10848 		ReplaceMetadata: true,
  10849 	}
  10850 
  10851 	function = "ComposeObject(destination, sources)"
  10852 	args["source"] = []minio.CopySrcOptions{src, src}
  10853 	args["destination"] = dst4
  10854 	_, err = c.ComposeObject(context.Background(), dst4, src, src)
  10855 	if err != nil {
  10856 		logError(testName, function, args, startTime, "", "ComposeObject failed", err)
  10857 		return
  10858 	}
  10859 
  10860 	// Check that no headers are copied in this case
  10861 	expectedHeaders = make(http.Header)
  10862 	expectedHeaders.Set("x-amz-meta-notmyheader", "notmyvalue")
  10863 	if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-4")) {
  10864 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10865 		return
  10866 	}
  10867 
  10868 	successLogger(testName, function, args, startTime).Info()
  10869 }
  10870 
  10871 func testUserMetadataCopyingV2() {
  10872 	// initialize logging params
  10873 	startTime := time.Now()
  10874 	testName := getFuncName()
  10875 	function := "CopyObject(destination, source)"
  10876 	args := map[string]interface{}{}
  10877 
  10878 	// Instantiate new minio client object
  10879 	c, err := minio.New(os.Getenv(serverEndpoint),
  10880 		&minio.Options{
  10881 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10882 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10883 		})
  10884 	if err != nil {
  10885 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  10886 		return
  10887 	}
  10888 
  10889 	// c.TraceOn(os.Stderr)
  10890 	testUserMetadataCopyingWrapper(c)
  10891 }
  10892 
  10893 func testStorageClassMetadataPutObject() {
  10894 	// initialize logging params
  10895 	startTime := time.Now()
  10896 	function := "testStorageClassMetadataPutObject()"
  10897 	args := map[string]interface{}{}
  10898 	testName := getFuncName()
  10899 
  10900 	// Instantiate new minio client object
  10901 	c, err := minio.New(os.Getenv(serverEndpoint),
  10902 		&minio.Options{
  10903 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10904 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10905 		})
  10906 	if err != nil {
  10907 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10908 		return
  10909 	}
  10910 
  10911 	// Generate a new random bucket name.
  10912 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  10913 	// Make a new bucket in 'us-east-1' (source bucket).
  10914 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  10915 	if err != nil {
  10916 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  10917 		return
  10918 	}
  10919 
  10920 	defer cleanupBucket(bucketName, c)
  10921 
  10922 	fetchMeta := func(object string) (h http.Header) {
  10923 		objInfo, err := c.StatObject(context.Background(), bucketName, object, minio.StatObjectOptions{})
  10924 		if err != nil {
  10925 			logError(testName, function, args, startTime, "", "Stat failed", err)
  10926 			return
  10927 		}
  10928 		h = make(http.Header)
  10929 		for k, vs := range objInfo.Metadata {
  10930 			if strings.HasPrefix(strings.ToLower(k), "x-amz-storage-class") {
  10931 				for _, v := range vs {
  10932 					h.Add(k, v)
  10933 				}
  10934 			}
  10935 		}
  10936 		return h
  10937 	}
  10938 
  10939 	metadata := make(http.Header)
  10940 	metadata.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
  10941 
  10942 	emptyMetadata := make(http.Header)
  10943 
  10944 	const srcSize = 1024 * 1024
  10945 	buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 1MiB
  10946 
  10947 	_, err = c.PutObject(context.Background(), bucketName, "srcObjectRRSClass",
  10948 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "REDUCED_REDUNDANCY"})
  10949 	if err != nil {
  10950 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  10951 		return
  10952 	}
  10953 
  10954 	// Get the returned metadata
  10955 	returnedMeta := fetchMeta("srcObjectRRSClass")
  10956 
  10957 	// The response metada should either be equal to metadata (with REDUCED_REDUNDANCY) or emptyMetadata (in case of gateways)
  10958 	if !reflect.DeepEqual(metadata, returnedMeta) && !reflect.DeepEqual(emptyMetadata, returnedMeta) {
  10959 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  10960 		return
  10961 	}
  10962 
  10963 	metadata = make(http.Header)
  10964 	metadata.Set("x-amz-storage-class", "STANDARD")
  10965 
  10966 	_, err = c.PutObject(context.Background(), bucketName, "srcObjectSSClass",
  10967 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "STANDARD"})
  10968 	if err != nil {
  10969 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  10970 		return
  10971 	}
  10972 	if reflect.DeepEqual(metadata, fetchMeta("srcObjectSSClass")) {
  10973 		logError(testName, function, args, startTime, "", "Metadata verification failed, STANDARD storage class should not be a part of response metadata", err)
  10974 		return
  10975 	}
  10976 
  10977 	successLogger(testName, function, args, startTime).Info()
  10978 }
  10979 
  10980 func testStorageClassInvalidMetadataPutObject() {
  10981 	// initialize logging params
  10982 	startTime := time.Now()
  10983 	function := "testStorageClassInvalidMetadataPutObject()"
  10984 	args := map[string]interface{}{}
  10985 	testName := getFuncName()
  10986 
  10987 	// Instantiate new minio client object
  10988 	c, err := minio.New(os.Getenv(serverEndpoint),
  10989 		&minio.Options{
  10990 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  10991 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  10992 		})
  10993 	if err != nil {
  10994 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  10995 		return
  10996 	}
  10997 
  10998 	// Generate a new random bucket name.
  10999 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  11000 	// Make a new bucket in 'us-east-1' (source bucket).
  11001 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11002 	if err != nil {
  11003 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11004 		return
  11005 	}
  11006 
  11007 	defer cleanupBucket(bucketName, c)
  11008 
  11009 	const srcSize = 1024 * 1024
  11010 	buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 1MiB
  11011 
  11012 	_, err = c.PutObject(context.Background(), bucketName, "srcObjectRRSClass",
  11013 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "INVALID_STORAGE_CLASS"})
  11014 	if err == nil {
  11015 		logError(testName, function, args, startTime, "", "PutObject with invalid storage class passed, was expected to fail", err)
  11016 		return
  11017 	}
  11018 
  11019 	successLogger(testName, function, args, startTime).Info()
  11020 }
  11021 
  11022 func testStorageClassMetadataCopyObject() {
  11023 	// initialize logging params
  11024 	startTime := time.Now()
  11025 	function := "testStorageClassMetadataCopyObject()"
  11026 	args := map[string]interface{}{}
  11027 	testName := getFuncName()
  11028 
  11029 	// Instantiate new minio client object
  11030 	c, err := minio.New(os.Getenv(serverEndpoint),
  11031 		&minio.Options{
  11032 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11033 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11034 		})
  11035 	if err != nil {
  11036 		logError(testName, function, args, startTime, "", "MinIO v4 client object creation failed", err)
  11037 		return
  11038 	}
  11039 
  11040 	// Generate a new random bucket name.
  11041 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  11042 	// Make a new bucket in 'us-east-1' (source bucket).
  11043 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11044 	if err != nil {
  11045 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11046 		return
  11047 	}
  11048 
  11049 	defer cleanupBucket(bucketName, c)
  11050 
  11051 	fetchMeta := func(object string) (h http.Header) {
  11052 		objInfo, err := c.StatObject(context.Background(), bucketName, object, minio.StatObjectOptions{})
  11053 		args["bucket"] = bucketName
  11054 		args["object"] = object
  11055 		if err != nil {
  11056 			logError(testName, function, args, startTime, "", "Stat failed", err)
  11057 			return
  11058 		}
  11059 		h = make(http.Header)
  11060 		for k, vs := range objInfo.Metadata {
  11061 			if strings.HasPrefix(strings.ToLower(k), "x-amz-storage-class") {
  11062 				for _, v := range vs {
  11063 					h.Add(k, v)
  11064 				}
  11065 			}
  11066 		}
  11067 		return h
  11068 	}
  11069 
  11070 	metadata := make(http.Header)
  11071 	metadata.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
  11072 
  11073 	emptyMetadata := make(http.Header)
  11074 
  11075 	const srcSize = 1024 * 1024
  11076 	buf := bytes.Repeat([]byte("abcde"), srcSize)
  11077 
  11078 	// Put an object with RRS Storage class
  11079 	_, err = c.PutObject(context.Background(), bucketName, "srcObjectRRSClass",
  11080 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "REDUCED_REDUNDANCY"})
  11081 	if err != nil {
  11082 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  11083 		return
  11084 	}
  11085 
  11086 	// Make server side copy of object uploaded in previous step
  11087 	src := minio.CopySrcOptions{
  11088 		Bucket: bucketName,
  11089 		Object: "srcObjectRRSClass",
  11090 	}
  11091 	dst := minio.CopyDestOptions{
  11092 		Bucket: bucketName,
  11093 		Object: "srcObjectRRSClassCopy",
  11094 	}
  11095 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
  11096 		logError(testName, function, args, startTime, "", "CopyObject failed on RRS", err)
  11097 		return
  11098 	}
  11099 
  11100 	// Get the returned metadata
  11101 	returnedMeta := fetchMeta("srcObjectRRSClassCopy")
  11102 
  11103 	// The response metada should either be equal to metadata (with REDUCED_REDUNDANCY) or emptyMetadata (in case of gateways)
  11104 	if !reflect.DeepEqual(metadata, returnedMeta) && !reflect.DeepEqual(emptyMetadata, returnedMeta) {
  11105 		logError(testName, function, args, startTime, "", "Metadata match failed", err)
  11106 		return
  11107 	}
  11108 
  11109 	metadata = make(http.Header)
  11110 	metadata.Set("x-amz-storage-class", "STANDARD")
  11111 
  11112 	// Put an object with Standard Storage class
  11113 	_, err = c.PutObject(context.Background(), bucketName, "srcObjectSSClass",
  11114 		bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "STANDARD"})
  11115 	if err != nil {
  11116 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  11117 		return
  11118 	}
  11119 
  11120 	// Make server side copy of object uploaded in previous step
  11121 	src = minio.CopySrcOptions{
  11122 		Bucket: bucketName,
  11123 		Object: "srcObjectSSClass",
  11124 	}
  11125 	dst = minio.CopyDestOptions{
  11126 		Bucket: bucketName,
  11127 		Object: "srcObjectSSClassCopy",
  11128 	}
  11129 	if _, err = c.CopyObject(context.Background(), dst, src); err != nil {
  11130 		logError(testName, function, args, startTime, "", "CopyObject failed on SS", err)
  11131 		return
  11132 	}
  11133 	// Fetch the meta data of copied object
  11134 	if reflect.DeepEqual(metadata, fetchMeta("srcObjectSSClassCopy")) {
  11135 		logError(testName, function, args, startTime, "", "Metadata verification failed, STANDARD storage class should not be a part of response metadata", err)
  11136 		return
  11137 	}
  11138 
  11139 	successLogger(testName, function, args, startTime).Info()
  11140 }
  11141 
  11142 // Test put object with size -1 byte object.
  11143 func testPutObjectNoLengthV2() {
  11144 	// initialize logging params
  11145 	startTime := time.Now()
  11146 	testName := getFuncName()
  11147 	function := "PutObject(bucketName, objectName, reader, size, opts)"
  11148 	args := map[string]interface{}{
  11149 		"bucketName": "",
  11150 		"objectName": "",
  11151 		"size":       -1,
  11152 		"opts":       "",
  11153 	}
  11154 
  11155 	// Seed random based on current time.
  11156 	rand.Seed(time.Now().Unix())
  11157 
  11158 	// Instantiate new minio client object.
  11159 	c, err := minio.New(os.Getenv(serverEndpoint),
  11160 		&minio.Options{
  11161 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11162 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11163 		})
  11164 	if err != nil {
  11165 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  11166 		return
  11167 	}
  11168 
  11169 	// Enable tracing, write to stderr.
  11170 	// c.TraceOn(os.Stderr)
  11171 
  11172 	// Set user agent.
  11173 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  11174 
  11175 	// Generate a new random bucket name.
  11176 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  11177 	args["bucketName"] = bucketName
  11178 
  11179 	// Make a new bucket.
  11180 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11181 	if err != nil {
  11182 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11183 		return
  11184 	}
  11185 
  11186 	defer cleanupBucket(bucketName, c)
  11187 
  11188 	objectName := bucketName + "unique"
  11189 	args["objectName"] = objectName
  11190 
  11191 	bufSize := dataFileMap["datafile-129-MB"]
  11192 	reader := getDataReader("datafile-129-MB")
  11193 	defer reader.Close()
  11194 	args["size"] = bufSize
  11195 
  11196 	// Upload an object.
  11197 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, -1, minio.PutObjectOptions{})
  11198 	if err != nil {
  11199 		logError(testName, function, args, startTime, "", "PutObjectWithSize failed", err)
  11200 		return
  11201 	}
  11202 
  11203 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
  11204 	if err != nil {
  11205 		logError(testName, function, args, startTime, "", "StatObject failed", err)
  11206 		return
  11207 	}
  11208 
  11209 	if st.Size != int64(bufSize) {
  11210 		logError(testName, function, args, startTime, "", "Expected upload object size "+string(bufSize)+" got "+string(st.Size), err)
  11211 		return
  11212 	}
  11213 
  11214 	successLogger(testName, function, args, startTime).Info()
  11215 }
  11216 
  11217 // Test put objects of unknown size.
  11218 func testPutObjectsUnknownV2() {
  11219 	// initialize logging params
  11220 	startTime := time.Now()
  11221 	testName := getFuncName()
  11222 	function := "PutObject(bucketName, objectName, reader,size,opts)"
  11223 	args := map[string]interface{}{
  11224 		"bucketName": "",
  11225 		"objectName": "",
  11226 		"size":       "",
  11227 		"opts":       "",
  11228 	}
  11229 
  11230 	// Seed random based on current time.
  11231 	rand.Seed(time.Now().Unix())
  11232 
  11233 	// Instantiate new minio client object.
  11234 	c, err := minio.New(os.Getenv(serverEndpoint),
  11235 		&minio.Options{
  11236 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11237 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11238 		})
  11239 	if err != nil {
  11240 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  11241 		return
  11242 	}
  11243 
  11244 	// Enable tracing, write to stderr.
  11245 	// c.TraceOn(os.Stderr)
  11246 
  11247 	// Set user agent.
  11248 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  11249 
  11250 	// Generate a new random bucket name.
  11251 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  11252 	args["bucketName"] = bucketName
  11253 
  11254 	// Make a new bucket.
  11255 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11256 	if err != nil {
  11257 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11258 		return
  11259 	}
  11260 
  11261 	defer cleanupBucket(bucketName, c)
  11262 
  11263 	// Issues are revealed by trying to upload multiple files of unknown size
  11264 	// sequentially (on 4GB machines)
  11265 	for i := 1; i <= 4; i++ {
  11266 		// Simulate that we could be receiving byte slices of data that we want
  11267 		// to upload as a file
  11268 		rpipe, wpipe := io.Pipe()
  11269 		defer rpipe.Close()
  11270 		go func() {
  11271 			b := []byte("test")
  11272 			wpipe.Write(b)
  11273 			wpipe.Close()
  11274 		}()
  11275 
  11276 		// Upload the object.
  11277 		objectName := fmt.Sprintf("%sunique%d", bucketName, i)
  11278 		args["objectName"] = objectName
  11279 
  11280 		ui, err := c.PutObject(context.Background(), bucketName, objectName, rpipe, -1, minio.PutObjectOptions{})
  11281 		if err != nil {
  11282 			logError(testName, function, args, startTime, "", "PutObjectStreaming failed", err)
  11283 			return
  11284 		}
  11285 
  11286 		if ui.Size != 4 {
  11287 			logError(testName, function, args, startTime, "", "Expected upload object size "+string(4)+" got "+string(ui.Size), nil)
  11288 			return
  11289 		}
  11290 
  11291 		st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
  11292 		if err != nil {
  11293 			logError(testName, function, args, startTime, "", "StatObjectStreaming failed", err)
  11294 			return
  11295 		}
  11296 
  11297 		if st.Size != int64(4) {
  11298 			logError(testName, function, args, startTime, "", "Expected upload object size "+string(4)+" got "+string(st.Size), err)
  11299 			return
  11300 		}
  11301 
  11302 	}
  11303 
  11304 	successLogger(testName, function, args, startTime).Info()
  11305 }
  11306 
  11307 // Test put object with 0 byte object.
  11308 func testPutObject0ByteV2() {
  11309 	// initialize logging params
  11310 	startTime := time.Now()
  11311 	testName := getFuncName()
  11312 	function := "PutObject(bucketName, objectName, reader, size, opts)"
  11313 	args := map[string]interface{}{
  11314 		"bucketName": "",
  11315 		"objectName": "",
  11316 		"size":       0,
  11317 		"opts":       "",
  11318 	}
  11319 
  11320 	// Seed random based on current time.
  11321 	rand.Seed(time.Now().Unix())
  11322 
  11323 	// Instantiate new minio client object.
  11324 	c, err := minio.New(os.Getenv(serverEndpoint),
  11325 		&minio.Options{
  11326 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11327 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11328 		})
  11329 	if err != nil {
  11330 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  11331 		return
  11332 	}
  11333 
  11334 	// Enable tracing, write to stderr.
  11335 	// c.TraceOn(os.Stderr)
  11336 
  11337 	// Set user agent.
  11338 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  11339 
  11340 	// Generate a new random bucket name.
  11341 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  11342 	args["bucketName"] = bucketName
  11343 
  11344 	// Make a new bucket.
  11345 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11346 	if err != nil {
  11347 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11348 		return
  11349 	}
  11350 
  11351 	defer cleanupBucket(bucketName, c)
  11352 
  11353 	objectName := bucketName + "unique"
  11354 	args["objectName"] = objectName
  11355 	args["opts"] = minio.PutObjectOptions{}
  11356 
  11357 	// Upload an object.
  11358 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader([]byte("")), 0, minio.PutObjectOptions{})
  11359 	if err != nil {
  11360 		logError(testName, function, args, startTime, "", "PutObjectWithSize failed", err)
  11361 		return
  11362 	}
  11363 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
  11364 	if err != nil {
  11365 		logError(testName, function, args, startTime, "", "StatObjectWithSize failed", err)
  11366 		return
  11367 	}
  11368 	if st.Size != 0 {
  11369 		logError(testName, function, args, startTime, "", "Expected upload object size 0 but got "+string(st.Size), err)
  11370 		return
  11371 	}
  11372 
  11373 	successLogger(testName, function, args, startTime).Info()
  11374 }
  11375 
  11376 // Test expected error cases
  11377 func testComposeObjectErrorCases() {
  11378 	// initialize logging params
  11379 	startTime := time.Now()
  11380 	testName := getFuncName()
  11381 	function := "ComposeObject(destination, sourceList)"
  11382 	args := map[string]interface{}{}
  11383 
  11384 	// Instantiate new minio client object
  11385 	c, err := minio.New(os.Getenv(serverEndpoint),
  11386 		&minio.Options{
  11387 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11388 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11389 		})
  11390 	if err != nil {
  11391 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
  11392 		return
  11393 	}
  11394 
  11395 	testComposeObjectErrorCasesWrapper(c)
  11396 }
  11397 
  11398 // Test concatenating multiple 10K objects V4
  11399 func testCompose10KSources() {
  11400 	// initialize logging params
  11401 	startTime := time.Now()
  11402 	testName := getFuncName()
  11403 	function := "ComposeObject(destination, sourceList)"
  11404 	args := map[string]interface{}{}
  11405 
  11406 	// Instantiate new minio client object
  11407 	c, err := minio.New(os.Getenv(serverEndpoint),
  11408 		&minio.Options{
  11409 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11410 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11411 		})
  11412 	if err != nil {
  11413 		logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
  11414 		return
  11415 	}
  11416 
  11417 	testComposeMultipleSources(c)
  11418 }
  11419 
  11420 // Tests comprehensive list of all methods.
  11421 func testFunctionalV2() {
  11422 	// initialize logging params
  11423 	startTime := time.Now()
  11424 	testName := getFuncName()
  11425 	function := "testFunctionalV2()"
  11426 	functionAll := ""
  11427 	args := map[string]interface{}{}
  11428 
  11429 	// Seed random based on current time.
  11430 	rand.Seed(time.Now().Unix())
  11431 
  11432 	c, err := minio.New(os.Getenv(serverEndpoint),
  11433 		&minio.Options{
  11434 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11435 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11436 		})
  11437 	if err != nil {
  11438 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  11439 		return
  11440 	}
  11441 
  11442 	// Enable to debug
  11443 	// c.TraceOn(os.Stderr)
  11444 
  11445 	// Set user agent.
  11446 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  11447 
  11448 	// Generate a new random bucket name.
  11449 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  11450 	location := "us-east-1"
  11451 	// Make a new bucket.
  11452 	function = "MakeBucket(bucketName, location)"
  11453 	functionAll = "MakeBucket(bucketName, location)"
  11454 	args = map[string]interface{}{
  11455 		"bucketName": bucketName,
  11456 		"location":   location,
  11457 	}
  11458 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: location})
  11459 	if err != nil {
  11460 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11461 		return
  11462 	}
  11463 
  11464 	defer cleanupBucket(bucketName, c)
  11465 
  11466 	// Generate a random file name.
  11467 	fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  11468 	file, err := os.Create(fileName)
  11469 	if err != nil {
  11470 		logError(testName, function, args, startTime, "", "file create failed", err)
  11471 		return
  11472 	}
  11473 	for i := 0; i < 3; i++ {
  11474 		buf := make([]byte, rand.Intn(1<<19))
  11475 		_, err = file.Write(buf)
  11476 		if err != nil {
  11477 			logError(testName, function, args, startTime, "", "file write failed", err)
  11478 			return
  11479 		}
  11480 	}
  11481 	file.Close()
  11482 
  11483 	// Verify if bucket exits and you have access.
  11484 	var exists bool
  11485 	function = "BucketExists(bucketName)"
  11486 	functionAll += ", " + function
  11487 	args = map[string]interface{}{
  11488 		"bucketName": bucketName,
  11489 	}
  11490 	exists, err = c.BucketExists(context.Background(), bucketName)
  11491 	if err != nil {
  11492 		logError(testName, function, args, startTime, "", "BucketExists failed", err)
  11493 		return
  11494 	}
  11495 	if !exists {
  11496 		logError(testName, function, args, startTime, "", "Could not find existing bucket "+bucketName, err)
  11497 		return
  11498 	}
  11499 
  11500 	// Make the bucket 'public read/write'.
  11501 	function = "SetBucketPolicy(bucketName, bucketPolicy)"
  11502 	functionAll += ", " + function
  11503 
  11504 	readWritePolicy := `{"Version": "2012-10-17","Statement": [{"Action": ["s3:ListBucketMultipartUploads", "s3:ListBucket"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::` + bucketName + `"],"Sid": ""}]}`
  11505 
  11506 	args = map[string]interface{}{
  11507 		"bucketName":   bucketName,
  11508 		"bucketPolicy": readWritePolicy,
  11509 	}
  11510 	err = c.SetBucketPolicy(context.Background(), bucketName, readWritePolicy)
  11511 
  11512 	if err != nil {
  11513 		logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
  11514 		return
  11515 	}
  11516 
  11517 	// List all buckets.
  11518 	function = "ListBuckets()"
  11519 	functionAll += ", " + function
  11520 	args = nil
  11521 	buckets, err := c.ListBuckets(context.Background())
  11522 	if len(buckets) == 0 {
  11523 		logError(testName, function, args, startTime, "", "List buckets cannot be empty", err)
  11524 		return
  11525 	}
  11526 	if err != nil {
  11527 		logError(testName, function, args, startTime, "", "ListBuckets failed", err)
  11528 		return
  11529 	}
  11530 
  11531 	// Verify if previously created bucket is listed in list buckets.
  11532 	bucketFound := false
  11533 	for _, bucket := range buckets {
  11534 		if bucket.Name == bucketName {
  11535 			bucketFound = true
  11536 		}
  11537 	}
  11538 
  11539 	// If bucket not found error out.
  11540 	if !bucketFound {
  11541 		logError(testName, function, args, startTime, "", "Bucket "+bucketName+"not found", err)
  11542 		return
  11543 	}
  11544 
  11545 	objectName := bucketName + "unique"
  11546 
  11547 	// Generate data
  11548 	buf := bytes.Repeat([]byte("n"), rand.Intn(1<<19))
  11549 
  11550 	args = map[string]interface{}{
  11551 		"bucketName":  bucketName,
  11552 		"objectName":  objectName,
  11553 		"contentType": "",
  11554 	}
  11555 	_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
  11556 	if err != nil {
  11557 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  11558 		return
  11559 	}
  11560 
  11561 	st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
  11562 	if err != nil {
  11563 		logError(testName, function, args, startTime, "", "StatObject failed", err)
  11564 		return
  11565 	}
  11566 	if st.Size != int64(len(buf)) {
  11567 		logError(testName, function, args, startTime, "", "Expected uploaded object length "+string(len(buf))+" got "+string(st.Size), err)
  11568 		return
  11569 	}
  11570 
  11571 	objectNameNoLength := objectName + "-nolength"
  11572 	args["objectName"] = objectNameNoLength
  11573 	_, err = c.PutObject(context.Background(), bucketName, objectNameNoLength, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  11574 	if err != nil {
  11575 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  11576 		return
  11577 	}
  11578 	st, err = c.StatObject(context.Background(), bucketName, objectNameNoLength, minio.StatObjectOptions{})
  11579 	if err != nil {
  11580 		logError(testName, function, args, startTime, "", "StatObject failed", err)
  11581 		return
  11582 	}
  11583 	if st.Size != int64(len(buf)) {
  11584 		logError(testName, function, args, startTime, "", "Expected uploaded object length "+string(len(buf))+" got "+string(st.Size), err)
  11585 		return
  11586 	}
  11587 
  11588 	// Instantiate a done channel to close all listing.
  11589 	doneCh := make(chan struct{})
  11590 	defer close(doneCh)
  11591 
  11592 	objFound := false
  11593 	isRecursive := true // Recursive is true.
  11594 	function = "ListObjects(bucketName, objectName, isRecursive, doneCh)"
  11595 	functionAll += ", " + function
  11596 	args = map[string]interface{}{
  11597 		"bucketName":  bucketName,
  11598 		"objectName":  objectName,
  11599 		"isRecursive": isRecursive,
  11600 	}
  11601 	for obj := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{UseV1: true, Prefix: objectName, Recursive: isRecursive}) {
  11602 		if obj.Key == objectName {
  11603 			objFound = true
  11604 			break
  11605 		}
  11606 	}
  11607 	if !objFound {
  11608 		logError(testName, function, args, startTime, "", "Could not find existing object "+objectName, err)
  11609 		return
  11610 	}
  11611 
  11612 	incompObjNotFound := true
  11613 	function = "ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)"
  11614 	functionAll += ", " + function
  11615 	args = map[string]interface{}{
  11616 		"bucketName":  bucketName,
  11617 		"objectName":  objectName,
  11618 		"isRecursive": isRecursive,
  11619 	}
  11620 	for objIncompl := range c.ListIncompleteUploads(context.Background(), bucketName, objectName, isRecursive) {
  11621 		if objIncompl.Key != "" {
  11622 			incompObjNotFound = false
  11623 			break
  11624 		}
  11625 	}
  11626 	if !incompObjNotFound {
  11627 		logError(testName, function, args, startTime, "", "Unexpected dangling incomplete upload found", err)
  11628 		return
  11629 	}
  11630 
  11631 	function = "GetObject(bucketName, objectName)"
  11632 	functionAll += ", " + function
  11633 	args = map[string]interface{}{
  11634 		"bucketName": bucketName,
  11635 		"objectName": objectName,
  11636 	}
  11637 	newReader, err := c.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
  11638 	if err != nil {
  11639 		logError(testName, function, args, startTime, "", "GetObject failed", err)
  11640 		return
  11641 	}
  11642 
  11643 	newReadBytes, err := io.ReadAll(newReader)
  11644 	if err != nil {
  11645 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
  11646 		return
  11647 	}
  11648 	newReader.Close()
  11649 
  11650 	if !bytes.Equal(newReadBytes, buf) {
  11651 		logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  11652 		return
  11653 	}
  11654 
  11655 	function = "FGetObject(bucketName, objectName, fileName)"
  11656 	functionAll += ", " + function
  11657 	args = map[string]interface{}{
  11658 		"bucketName": bucketName,
  11659 		"objectName": objectName,
  11660 		"fileName":   fileName + "-f",
  11661 	}
  11662 	err = c.FGetObject(context.Background(), bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  11663 	if err != nil {
  11664 		logError(testName, function, args, startTime, "", "FgetObject failed", err)
  11665 		return
  11666 	}
  11667 
  11668 	// Generate presigned HEAD object url.
  11669 	function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
  11670 	functionAll += ", " + function
  11671 	args = map[string]interface{}{
  11672 		"bucketName": bucketName,
  11673 		"objectName": objectName,
  11674 		"expires":    3600 * time.Second,
  11675 	}
  11676 	presignedHeadURL, err := c.PresignedHeadObject(context.Background(), bucketName, objectName, 3600*time.Second, nil)
  11677 	if err != nil {
  11678 		logError(testName, function, args, startTime, "", "PresignedHeadObject failed", err)
  11679 		return
  11680 	}
  11681 
  11682 	transport, err := minio.DefaultTransport(mustParseBool(os.Getenv(enableHTTPS)))
  11683 	if err != nil {
  11684 		logError(testName, function, args, startTime, "", "DefaultTransport failed", err)
  11685 		return
  11686 	}
  11687 
  11688 	httpClient := &http.Client{
  11689 		// Setting a sensible time out of 30secs to wait for response
  11690 		// headers. Request is pro-actively canceled after 30secs
  11691 		// with no response.
  11692 		Timeout:   30 * time.Second,
  11693 		Transport: transport,
  11694 	}
  11695 
  11696 	req, err := http.NewRequest(http.MethodHead, presignedHeadURL.String(), nil)
  11697 	if err != nil {
  11698 		logError(testName, function, args, startTime, "", "PresignedHeadObject URL head request failed", err)
  11699 		return
  11700 	}
  11701 
  11702 	// Verify if presigned url works.
  11703 	resp, err := httpClient.Do(req)
  11704 	if err != nil {
  11705 		logError(testName, function, args, startTime, "", "PresignedHeadObject URL head request failed", err)
  11706 		return
  11707 	}
  11708 	if resp.StatusCode != http.StatusOK {
  11709 		logError(testName, function, args, startTime, "", "PresignedHeadObject URL returns status "+string(resp.StatusCode), err)
  11710 		return
  11711 	}
  11712 	if resp.Header.Get("ETag") == "" {
  11713 		logError(testName, function, args, startTime, "", "Got empty ETag", err)
  11714 		return
  11715 	}
  11716 	resp.Body.Close()
  11717 
  11718 	// Generate presigned GET object url.
  11719 	function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
  11720 	functionAll += ", " + function
  11721 	args = map[string]interface{}{
  11722 		"bucketName": bucketName,
  11723 		"objectName": objectName,
  11724 		"expires":    3600 * time.Second,
  11725 	}
  11726 	presignedGetURL, err := c.PresignedGetObject(context.Background(), bucketName, objectName, 3600*time.Second, nil)
  11727 	if err != nil {
  11728 		logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  11729 		return
  11730 	}
  11731 
  11732 	// Verify if presigned url works.
  11733 	req, err = http.NewRequest(http.MethodGet, presignedGetURL.String(), nil)
  11734 	if err != nil {
  11735 		logError(testName, function, args, startTime, "", "PresignedGetObject request incorrect", err)
  11736 		return
  11737 	}
  11738 
  11739 	resp, err = httpClient.Do(req)
  11740 	if err != nil {
  11741 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  11742 		return
  11743 	}
  11744 
  11745 	if resp.StatusCode != http.StatusOK {
  11746 		logError(testName, function, args, startTime, "", "PresignedGetObject URL returns status "+string(resp.StatusCode), err)
  11747 		return
  11748 	}
  11749 	newPresignedBytes, err := io.ReadAll(resp.Body)
  11750 	if err != nil {
  11751 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
  11752 		return
  11753 	}
  11754 	resp.Body.Close()
  11755 	if !bytes.Equal(newPresignedBytes, buf) {
  11756 		logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  11757 		return
  11758 	}
  11759 
  11760 	// Set request parameters.
  11761 	reqParams := make(url.Values)
  11762 	reqParams.Set("response-content-disposition", "attachment; filename=\"test.txt\"")
  11763 	// Generate presigned GET object url.
  11764 	args["reqParams"] = reqParams
  11765 	presignedGetURL, err = c.PresignedGetObject(context.Background(), bucketName, objectName, 3600*time.Second, reqParams)
  11766 	if err != nil {
  11767 		logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  11768 		return
  11769 	}
  11770 
  11771 	// Verify if presigned url works.
  11772 	req, err = http.NewRequest(http.MethodGet, presignedGetURL.String(), nil)
  11773 	if err != nil {
  11774 		logError(testName, function, args, startTime, "", "PresignedGetObject request incorrect", err)
  11775 		return
  11776 	}
  11777 
  11778 	resp, err = httpClient.Do(req)
  11779 	if err != nil {
  11780 		logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  11781 		return
  11782 	}
  11783 
  11784 	if resp.StatusCode != http.StatusOK {
  11785 		logError(testName, function, args, startTime, "", "PresignedGetObject URL returns status "+string(resp.StatusCode), err)
  11786 		return
  11787 	}
  11788 	newPresignedBytes, err = io.ReadAll(resp.Body)
  11789 	if err != nil {
  11790 		logError(testName, function, args, startTime, "", "ReadAll failed", err)
  11791 		return
  11792 	}
  11793 	if !bytes.Equal(newPresignedBytes, buf) {
  11794 		logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  11795 		return
  11796 	}
  11797 	// Verify content disposition.
  11798 	if resp.Header.Get("Content-Disposition") != "attachment; filename=\"test.txt\"" {
  11799 		logError(testName, function, args, startTime, "", "wrong Content-Disposition received ", err)
  11800 		return
  11801 	}
  11802 
  11803 	function = "PresignedPutObject(bucketName, objectName, expires)"
  11804 	functionAll += ", " + function
  11805 	args = map[string]interface{}{
  11806 		"bucketName": bucketName,
  11807 		"objectName": objectName + "-presigned",
  11808 		"expires":    3600 * time.Second,
  11809 	}
  11810 	presignedPutURL, err := c.PresignedPutObject(context.Background(), bucketName, objectName+"-presigned", 3600*time.Second)
  11811 	if err != nil {
  11812 		logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
  11813 		return
  11814 	}
  11815 
  11816 	// Generate data more than 32K
  11817 	buf = bytes.Repeat([]byte("1"), rand.Intn(1<<10)+32*1024)
  11818 
  11819 	req, err = http.NewRequest(http.MethodPut, presignedPutURL.String(), bytes.NewReader(buf))
  11820 	if err != nil {
  11821 		logError(testName, function, args, startTime, "", "HTTP request to PresignedPutObject URL failed", err)
  11822 		return
  11823 	}
  11824 
  11825 	resp, err = httpClient.Do(req)
  11826 	if err != nil {
  11827 		logError(testName, function, args, startTime, "", "HTTP request to PresignedPutObject URL failed", err)
  11828 		return
  11829 	}
  11830 
  11831 	// Download the uploaded object to verify
  11832 	args = map[string]interface{}{
  11833 		"bucketName": bucketName,
  11834 		"objectName": objectName + "-presigned",
  11835 	}
  11836 	newReader, err = c.GetObject(context.Background(), bucketName, objectName+"-presigned", minio.GetObjectOptions{})
  11837 	if err != nil {
  11838 		logError(testName, function, args, startTime, "", "GetObject of uploaded presigned object failed", err)
  11839 		return
  11840 	}
  11841 
  11842 	newReadBytes, err = io.ReadAll(newReader)
  11843 	if err != nil {
  11844 		logError(testName, function, args, startTime, "", "ReadAll failed during get on presigned put object", err)
  11845 		return
  11846 	}
  11847 	newReader.Close()
  11848 
  11849 	if !bytes.Equal(newReadBytes, buf) {
  11850 		logError(testName, function, args, startTime, "", "Bytes mismatch on presigned object upload verification", err)
  11851 		return
  11852 	}
  11853 
  11854 	function = "PresignHeader(method, bucketName, objectName, expires, reqParams, extraHeaders)"
  11855 	functionAll += ", " + function
  11856 	presignExtraHeaders := map[string][]string{
  11857 		"mysecret": {"abcxxx"},
  11858 	}
  11859 	args = map[string]interface{}{
  11860 		"method":       "PUT",
  11861 		"bucketName":   bucketName,
  11862 		"objectName":   objectName + "-presign-custom",
  11863 		"expires":      3600 * time.Second,
  11864 		"extraHeaders": presignExtraHeaders,
  11865 	}
  11866 	_, err = c.PresignHeader(context.Background(), "PUT", bucketName, objectName+"-presign-custom", 3600*time.Second, nil, presignExtraHeaders)
  11867 	if err == nil {
  11868 		logError(testName, function, args, startTime, "", "Presigned with extra headers succeeded", err)
  11869 		return
  11870 	}
  11871 
  11872 	os.Remove(fileName)
  11873 	os.Remove(fileName + "-f")
  11874 	successLogger(testName, functionAll, args, startTime).Info()
  11875 }
  11876 
  11877 // Test get object with GetObject with context
  11878 func testGetObjectContext() {
  11879 	// initialize logging params
  11880 	startTime := time.Now()
  11881 	testName := getFuncName()
  11882 	function := "GetObject(ctx, bucketName, objectName)"
  11883 	args := map[string]interface{}{
  11884 		"ctx":        "",
  11885 		"bucketName": "",
  11886 		"objectName": "",
  11887 	}
  11888 	// Seed random based on current time.
  11889 	rand.Seed(time.Now().Unix())
  11890 
  11891 	// Instantiate new minio client object.
  11892 	c, err := minio.New(os.Getenv(serverEndpoint),
  11893 		&minio.Options{
  11894 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11895 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11896 		})
  11897 	if err != nil {
  11898 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  11899 		return
  11900 	}
  11901 
  11902 	// Enable tracing, write to stderr.
  11903 	// c.TraceOn(os.Stderr)
  11904 
  11905 	// Set user agent.
  11906 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  11907 
  11908 	// Generate a new random bucket name.
  11909 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  11910 	args["bucketName"] = bucketName
  11911 
  11912 	// Make a new bucket.
  11913 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  11914 	if err != nil {
  11915 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  11916 		return
  11917 	}
  11918 
  11919 	defer cleanupBucket(bucketName, c)
  11920 
  11921 	bufSize := dataFileMap["datafile-33-kB"]
  11922 	reader := getDataReader("datafile-33-kB")
  11923 	defer reader.Close()
  11924 	// Save the data
  11925 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  11926 	args["objectName"] = objectName
  11927 
  11928 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  11929 	if err != nil {
  11930 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  11931 		return
  11932 	}
  11933 
  11934 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  11935 	args["ctx"] = ctx
  11936 	cancel()
  11937 
  11938 	r, err := c.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
  11939 	if err != nil {
  11940 		logError(testName, function, args, startTime, "", "GetObject failed unexpectedly", err)
  11941 		return
  11942 	}
  11943 
  11944 	if _, err = r.Stat(); err == nil {
  11945 		logError(testName, function, args, startTime, "", "GetObject should fail on short timeout", err)
  11946 		return
  11947 	}
  11948 	r.Close()
  11949 
  11950 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  11951 	args["ctx"] = ctx
  11952 	defer cancel()
  11953 
  11954 	// Read the data back
  11955 	r, err = c.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
  11956 	if err != nil {
  11957 		logError(testName, function, args, startTime, "", "GetObject failed", err)
  11958 		return
  11959 	}
  11960 
  11961 	st, err := r.Stat()
  11962 	if err != nil {
  11963 		logError(testName, function, args, startTime, "", "object Stat call failed", err)
  11964 		return
  11965 	}
  11966 	if st.Size != int64(bufSize) {
  11967 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match: want "+string(bufSize)+", got"+string(st.Size), err)
  11968 		return
  11969 	}
  11970 	if err := r.Close(); err != nil {
  11971 		logError(testName, function, args, startTime, "", "object Close() call failed", err)
  11972 		return
  11973 	}
  11974 
  11975 	successLogger(testName, function, args, startTime).Info()
  11976 }
  11977 
  11978 // Test get object with FGetObject with a user provided context
  11979 func testFGetObjectContext() {
  11980 	// initialize logging params
  11981 	startTime := time.Now()
  11982 	testName := getFuncName()
  11983 	function := "FGetObject(ctx, bucketName, objectName, fileName)"
  11984 	args := map[string]interface{}{
  11985 		"ctx":        "",
  11986 		"bucketName": "",
  11987 		"objectName": "",
  11988 		"fileName":   "",
  11989 	}
  11990 	// Seed random based on current time.
  11991 	rand.Seed(time.Now().Unix())
  11992 
  11993 	// Instantiate new minio client object.
  11994 	c, err := minio.New(os.Getenv(serverEndpoint),
  11995 		&minio.Options{
  11996 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  11997 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  11998 		})
  11999 	if err != nil {
  12000 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  12001 		return
  12002 	}
  12003 
  12004 	// Enable tracing, write to stderr.
  12005 	// c.TraceOn(os.Stderr)
  12006 
  12007 	// Set user agent.
  12008 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12009 
  12010 	// Generate a new random bucket name.
  12011 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12012 	args["bucketName"] = bucketName
  12013 
  12014 	// Make a new bucket.
  12015 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12016 	if err != nil {
  12017 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12018 		return
  12019 	}
  12020 
  12021 	defer cleanupBucket(bucketName, c)
  12022 
  12023 	bufSize := dataFileMap["datafile-1-MB"]
  12024 	reader := getDataReader("datafile-1-MB")
  12025 	defer reader.Close()
  12026 	// Save the data
  12027 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12028 	args["objectName"] = objectName
  12029 
  12030 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12031 	if err != nil {
  12032 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  12033 		return
  12034 	}
  12035 
  12036 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  12037 	args["ctx"] = ctx
  12038 	defer cancel()
  12039 
  12040 	fileName := "tempfile-context"
  12041 	args["fileName"] = fileName
  12042 	// Read the data back
  12043 	err = c.FGetObject(ctx, bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  12044 	if err == nil {
  12045 		logError(testName, function, args, startTime, "", "FGetObject should fail on short timeout", err)
  12046 		return
  12047 	}
  12048 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  12049 	defer cancel()
  12050 
  12051 	// Read the data back
  12052 	err = c.FGetObject(ctx, bucketName, objectName, fileName+"-fcontext", minio.GetObjectOptions{})
  12053 	if err != nil {
  12054 		logError(testName, function, args, startTime, "", "FGetObject with long timeout failed", err)
  12055 		return
  12056 	}
  12057 	if err = os.Remove(fileName + "-fcontext"); err != nil {
  12058 		logError(testName, function, args, startTime, "", "Remove file failed", err)
  12059 		return
  12060 	}
  12061 
  12062 	successLogger(testName, function, args, startTime).Info()
  12063 }
  12064 
  12065 // Test get object with GetObject with a user provided context
  12066 func testGetObjectRanges() {
  12067 	// initialize logging params
  12068 	startTime := time.Now()
  12069 	testName := getFuncName()
  12070 	function := "GetObject(ctx, bucketName, objectName, fileName)"
  12071 	args := map[string]interface{}{
  12072 		"ctx":        "",
  12073 		"bucketName": "",
  12074 		"objectName": "",
  12075 		"fileName":   "",
  12076 	}
  12077 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
  12078 	defer cancel()
  12079 
  12080 	rng := rand.NewSource(time.Now().UnixNano())
  12081 	// Instantiate new minio client object.
  12082 	c, err := minio.New(os.Getenv(serverEndpoint),
  12083 		&minio.Options{
  12084 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12085 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12086 		})
  12087 	if err != nil {
  12088 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  12089 		return
  12090 	}
  12091 
  12092 	// Enable tracing, write to stderr.
  12093 	// c.TraceOn(os.Stderr)
  12094 
  12095 	// Set user agent.
  12096 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12097 
  12098 	// Generate a new random bucket name.
  12099 	bucketName := randString(60, rng, "minio-go-test-")
  12100 	args["bucketName"] = bucketName
  12101 
  12102 	// Make a new bucket.
  12103 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12104 	if err != nil {
  12105 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12106 		return
  12107 	}
  12108 
  12109 	defer cleanupBucket(bucketName, c)
  12110 
  12111 	bufSize := dataFileMap["datafile-129-MB"]
  12112 	reader := getDataReader("datafile-129-MB")
  12113 	defer reader.Close()
  12114 	// Save the data
  12115 	objectName := randString(60, rng, "")
  12116 	args["objectName"] = objectName
  12117 
  12118 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12119 	if err != nil {
  12120 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  12121 		return
  12122 	}
  12123 
  12124 	// Read the data back
  12125 	tests := []struct {
  12126 		start int64
  12127 		end   int64
  12128 	}{
  12129 		{
  12130 			start: 1024,
  12131 			end:   1024 + 1<<20,
  12132 		},
  12133 		{
  12134 			start: 20e6,
  12135 			end:   20e6 + 10000,
  12136 		},
  12137 		{
  12138 			start: 40e6,
  12139 			end:   40e6 + 10000,
  12140 		},
  12141 		{
  12142 			start: 60e6,
  12143 			end:   60e6 + 10000,
  12144 		},
  12145 		{
  12146 			start: 80e6,
  12147 			end:   80e6 + 10000,
  12148 		},
  12149 		{
  12150 			start: 120e6,
  12151 			end:   int64(bufSize),
  12152 		},
  12153 	}
  12154 	for _, test := range tests {
  12155 		wantRC := getDataReader("datafile-129-MB")
  12156 		io.CopyN(io.Discard, wantRC, test.start)
  12157 		want := mustCrcReader(io.LimitReader(wantRC, test.end-test.start+1))
  12158 		opts := minio.GetObjectOptions{}
  12159 		opts.SetRange(test.start, test.end)
  12160 		args["opts"] = fmt.Sprintf("%+v", test)
  12161 		obj, err := c.GetObject(ctx, bucketName, objectName, opts)
  12162 		if err != nil {
  12163 			logError(testName, function, args, startTime, "", "FGetObject with long timeout failed", err)
  12164 			return
  12165 		}
  12166 		err = crcMatches(obj, want)
  12167 		if err != nil {
  12168 			logError(testName, function, args, startTime, "", fmt.Sprintf("GetObject offset %d -> %d", test.start, test.end), err)
  12169 			return
  12170 		}
  12171 	}
  12172 
  12173 	successLogger(testName, function, args, startTime).Info()
  12174 }
  12175 
  12176 // Test get object ACLs with GetObjectACL with custom provided context
  12177 func testGetObjectACLContext() {
  12178 	// initialize logging params
  12179 	startTime := time.Now()
  12180 	testName := getFuncName()
  12181 	function := "GetObjectACL(ctx, bucketName, objectName)"
  12182 	args := map[string]interface{}{
  12183 		"ctx":        "",
  12184 		"bucketName": "",
  12185 		"objectName": "",
  12186 	}
  12187 	// Seed random based on current time.
  12188 	rand.Seed(time.Now().Unix())
  12189 
  12190 	// Instantiate new minio client object.
  12191 	c, err := minio.New(os.Getenv(serverEndpoint),
  12192 		&minio.Options{
  12193 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12194 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12195 		})
  12196 	if err != nil {
  12197 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  12198 		return
  12199 	}
  12200 
  12201 	// Enable tracing, write to stderr.
  12202 	// c.TraceOn(os.Stderr)
  12203 
  12204 	// Set user agent.
  12205 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12206 
  12207 	// Generate a new random bucket name.
  12208 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12209 	args["bucketName"] = bucketName
  12210 
  12211 	// Make a new bucket.
  12212 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12213 	if err != nil {
  12214 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12215 		return
  12216 	}
  12217 
  12218 	defer cleanupBucket(bucketName, c)
  12219 
  12220 	bufSize := dataFileMap["datafile-1-MB"]
  12221 	reader := getDataReader("datafile-1-MB")
  12222 	defer reader.Close()
  12223 	// Save the data
  12224 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12225 	args["objectName"] = objectName
  12226 
  12227 	// Add meta data to add a canned acl
  12228 	metaData := map[string]string{
  12229 		"X-Amz-Acl": "public-read-write",
  12230 	}
  12231 
  12232 	_, err = c.PutObject(context.Background(), bucketName,
  12233 		objectName, reader, int64(bufSize),
  12234 		minio.PutObjectOptions{
  12235 			ContentType:  "binary/octet-stream",
  12236 			UserMetadata: metaData,
  12237 		})
  12238 
  12239 	if err != nil {
  12240 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  12241 		return
  12242 	}
  12243 
  12244 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  12245 	args["ctx"] = ctx
  12246 	defer cancel()
  12247 
  12248 	// Read the data back
  12249 	objectInfo, getObjectACLErr := c.GetObjectACL(ctx, bucketName, objectName)
  12250 	if getObjectACLErr != nil {
  12251 		logError(testName, function, args, startTime, "", "GetObjectACL failed. ", getObjectACLErr)
  12252 		return
  12253 	}
  12254 
  12255 	s, ok := objectInfo.Metadata["X-Amz-Acl"]
  12256 	if !ok {
  12257 		logError(testName, function, args, startTime, "", "GetObjectACL fail unable to find \"X-Amz-Acl\"", nil)
  12258 		return
  12259 	}
  12260 
  12261 	if len(s) != 1 {
  12262 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Acl\" canned acl expected \"1\" got "+fmt.Sprintf(`"%d"`, len(s)), nil)
  12263 		return
  12264 	}
  12265 
  12266 	// Do a very limited testing if this is not AWS S3
  12267 	if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
  12268 		if s[0] != "private" {
  12269 			logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Acl\" expected \"private\" but got"+fmt.Sprintf("%q", s[0]), nil)
  12270 			return
  12271 		}
  12272 
  12273 		successLogger(testName, function, args, startTime).Info()
  12274 		return
  12275 	}
  12276 
  12277 	if s[0] != "public-read-write" {
  12278 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Acl\" expected \"public-read-write\" but got"+fmt.Sprintf("%q", s[0]), nil)
  12279 		return
  12280 	}
  12281 
  12282 	bufSize = dataFileMap["datafile-1-MB"]
  12283 	reader2 := getDataReader("datafile-1-MB")
  12284 	defer reader2.Close()
  12285 	// Save the data
  12286 	objectName = randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12287 	args["objectName"] = objectName
  12288 
  12289 	// Add meta data to add a canned acl
  12290 	metaData = map[string]string{
  12291 		"X-Amz-Grant-Read":  "id=fooread@minio.go",
  12292 		"X-Amz-Grant-Write": "id=foowrite@minio.go",
  12293 	}
  12294 
  12295 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader2, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream", UserMetadata: metaData})
  12296 	if err != nil {
  12297 		logError(testName, function, args, startTime, "", "PutObject failed", err)
  12298 		return
  12299 	}
  12300 
  12301 	ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
  12302 	args["ctx"] = ctx
  12303 	defer cancel()
  12304 
  12305 	// Read the data back
  12306 	objectInfo, getObjectACLErr = c.GetObjectACL(ctx, bucketName, objectName)
  12307 	if getObjectACLErr == nil {
  12308 		logError(testName, function, args, startTime, "", "GetObjectACL fail", getObjectACLErr)
  12309 		return
  12310 	}
  12311 
  12312 	if len(objectInfo.Metadata) != 3 {
  12313 		logError(testName, function, args, startTime, "", "GetObjectACL fail expected \"3\" ACLs but got "+fmt.Sprintf(`"%d"`, len(objectInfo.Metadata)), nil)
  12314 		return
  12315 	}
  12316 
  12317 	s, ok = objectInfo.Metadata["X-Amz-Grant-Read"]
  12318 	if !ok {
  12319 		logError(testName, function, args, startTime, "", "GetObjectACL fail unable to find \"X-Amz-Grant-Read\"", nil)
  12320 		return
  12321 	}
  12322 
  12323 	if len(s) != 1 {
  12324 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Grant-Read\" acl expected \"1\" got "+fmt.Sprintf(`"%d"`, len(s)), nil)
  12325 		return
  12326 	}
  12327 
  12328 	if s[0] != "fooread@minio.go" {
  12329 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Grant-Read\" acl expected \"fooread@minio.go\" got "+fmt.Sprintf("%q", s), nil)
  12330 		return
  12331 	}
  12332 
  12333 	s, ok = objectInfo.Metadata["X-Amz-Grant-Write"]
  12334 	if !ok {
  12335 		logError(testName, function, args, startTime, "", "GetObjectACL fail unable to find \"X-Amz-Grant-Write\"", nil)
  12336 		return
  12337 	}
  12338 
  12339 	if len(s) != 1 {
  12340 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Grant-Write\" acl expected \"1\" got "+fmt.Sprintf(`"%d"`, len(s)), nil)
  12341 		return
  12342 	}
  12343 
  12344 	if s[0] != "foowrite@minio.go" {
  12345 		logError(testName, function, args, startTime, "", "GetObjectACL fail \"X-Amz-Grant-Write\" acl expected \"foowrite@minio.go\" got "+fmt.Sprintf("%q", s), nil)
  12346 		return
  12347 	}
  12348 
  12349 	successLogger(testName, function, args, startTime).Info()
  12350 }
  12351 
  12352 // Test validates putObject with context to see if request cancellation is honored for V2.
  12353 func testPutObjectContextV2() {
  12354 	// initialize logging params
  12355 	startTime := time.Now()
  12356 	testName := getFuncName()
  12357 	function := "PutObject(ctx, bucketName, objectName, reader, size, opts)"
  12358 	args := map[string]interface{}{
  12359 		"ctx":        "",
  12360 		"bucketName": "",
  12361 		"objectName": "",
  12362 		"size":       "",
  12363 		"opts":       "",
  12364 	}
  12365 	// Instantiate new minio client object.
  12366 	c, err := minio.New(os.Getenv(serverEndpoint),
  12367 		&minio.Options{
  12368 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12369 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12370 		})
  12371 	if err != nil {
  12372 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  12373 		return
  12374 	}
  12375 
  12376 	// Enable tracing, write to stderr.
  12377 	// c.TraceOn(os.Stderr)
  12378 
  12379 	// Set user agent.
  12380 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12381 
  12382 	// Make a new bucket.
  12383 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12384 	args["bucketName"] = bucketName
  12385 
  12386 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12387 	if err != nil {
  12388 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12389 		return
  12390 	}
  12391 	defer cleanupBucket(bucketName, c)
  12392 	bufSize := dataFileMap["datatfile-33-kB"]
  12393 	reader := getDataReader("datafile-33-kB")
  12394 	defer reader.Close()
  12395 
  12396 	objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
  12397 	args["objectName"] = objectName
  12398 
  12399 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  12400 	args["ctx"] = ctx
  12401 	args["size"] = bufSize
  12402 	defer cancel()
  12403 
  12404 	_, err = c.PutObject(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12405 	if err != nil {
  12406 		logError(testName, function, args, startTime, "", "PutObject with short timeout failed", err)
  12407 		return
  12408 	}
  12409 
  12410 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  12411 	args["ctx"] = ctx
  12412 
  12413 	defer cancel()
  12414 	reader = getDataReader("datafile-33-kB")
  12415 	defer reader.Close()
  12416 	_, err = c.PutObject(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12417 	if err != nil {
  12418 		logError(testName, function, args, startTime, "", "PutObject with long timeout failed", err)
  12419 		return
  12420 	}
  12421 
  12422 	successLogger(testName, function, args, startTime).Info()
  12423 }
  12424 
  12425 // Test get object with GetObject with custom context
  12426 func testGetObjectContextV2() {
  12427 	// initialize logging params
  12428 	startTime := time.Now()
  12429 	testName := getFuncName()
  12430 	function := "GetObject(ctx, bucketName, objectName)"
  12431 	args := map[string]interface{}{
  12432 		"ctx":        "",
  12433 		"bucketName": "",
  12434 		"objectName": "",
  12435 	}
  12436 	// Seed random based on current time.
  12437 	rand.Seed(time.Now().Unix())
  12438 
  12439 	// Instantiate new minio client object.
  12440 	c, err := minio.New(os.Getenv(serverEndpoint),
  12441 		&minio.Options{
  12442 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12443 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12444 		})
  12445 	if err != nil {
  12446 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  12447 		return
  12448 	}
  12449 
  12450 	// Enable tracing, write to stderr.
  12451 	// c.TraceOn(os.Stderr)
  12452 
  12453 	// Set user agent.
  12454 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12455 
  12456 	// Generate a new random bucket name.
  12457 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12458 	args["bucketName"] = bucketName
  12459 
  12460 	// Make a new bucket.
  12461 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12462 	if err != nil {
  12463 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12464 		return
  12465 	}
  12466 
  12467 	defer cleanupBucket(bucketName, c)
  12468 
  12469 	bufSize := dataFileMap["datafile-33-kB"]
  12470 	reader := getDataReader("datafile-33-kB")
  12471 	defer reader.Close()
  12472 	// Save the data
  12473 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12474 	args["objectName"] = objectName
  12475 
  12476 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12477 	if err != nil {
  12478 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  12479 		return
  12480 	}
  12481 
  12482 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  12483 	args["ctx"] = ctx
  12484 	cancel()
  12485 
  12486 	r, err := c.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
  12487 	if err != nil {
  12488 		logError(testName, function, args, startTime, "", "GetObject failed unexpectedly", err)
  12489 		return
  12490 	}
  12491 	if _, err = r.Stat(); err == nil {
  12492 		logError(testName, function, args, startTime, "", "GetObject should fail on short timeout", err)
  12493 		return
  12494 	}
  12495 	r.Close()
  12496 
  12497 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  12498 	defer cancel()
  12499 
  12500 	// Read the data back
  12501 	r, err = c.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
  12502 	if err != nil {
  12503 		logError(testName, function, args, startTime, "", "GetObject shouldn't fail on longer timeout", err)
  12504 		return
  12505 	}
  12506 
  12507 	st, err := r.Stat()
  12508 	if err != nil {
  12509 		logError(testName, function, args, startTime, "", "object Stat call failed", err)
  12510 		return
  12511 	}
  12512 	if st.Size != int64(bufSize) {
  12513 		logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
  12514 		return
  12515 	}
  12516 	if err := r.Close(); err != nil {
  12517 		logError(testName, function, args, startTime, "", " object Close() call failed", err)
  12518 		return
  12519 	}
  12520 
  12521 	successLogger(testName, function, args, startTime).Info()
  12522 }
  12523 
  12524 // Test get object with FGetObject with custom context
  12525 func testFGetObjectContextV2() {
  12526 	// initialize logging params
  12527 	startTime := time.Now()
  12528 	testName := getFuncName()
  12529 	function := "FGetObject(ctx, bucketName, objectName,fileName)"
  12530 	args := map[string]interface{}{
  12531 		"ctx":        "",
  12532 		"bucketName": "",
  12533 		"objectName": "",
  12534 		"fileName":   "",
  12535 	}
  12536 	// Seed random based on current time.
  12537 	rand.Seed(time.Now().Unix())
  12538 
  12539 	// Instantiate new minio client object.
  12540 	c, err := minio.New(os.Getenv(serverEndpoint),
  12541 		&minio.Options{
  12542 			Creds:  credentials.NewStaticV2(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12543 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12544 		})
  12545 	if err != nil {
  12546 		logError(testName, function, args, startTime, "", "MinIO client v2 object creation failed", err)
  12547 		return
  12548 	}
  12549 
  12550 	// Enable tracing, write to stderr.
  12551 	// c.TraceOn(os.Stderr)
  12552 
  12553 	// Set user agent.
  12554 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12555 
  12556 	// Generate a new random bucket name.
  12557 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12558 	args["bucketName"] = bucketName
  12559 
  12560 	// Make a new bucket.
  12561 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12562 	if err != nil {
  12563 		logError(testName, function, args, startTime, "", "MakeBucket call failed", err)
  12564 		return
  12565 	}
  12566 
  12567 	defer cleanupBucket(bucketName, c)
  12568 
  12569 	bufSize := dataFileMap["datatfile-1-MB"]
  12570 	reader := getDataReader("datafile-1-MB")
  12571 	defer reader.Close()
  12572 	// Save the data
  12573 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12574 	args["objectName"] = objectName
  12575 
  12576 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  12577 	if err != nil {
  12578 		logError(testName, function, args, startTime, "", "PutObject call failed", err)
  12579 		return
  12580 	}
  12581 
  12582 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  12583 	args["ctx"] = ctx
  12584 	defer cancel()
  12585 
  12586 	fileName := "tempfile-context"
  12587 	args["fileName"] = fileName
  12588 
  12589 	// Read the data back
  12590 	err = c.FGetObject(ctx, bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  12591 	if err == nil {
  12592 		logError(testName, function, args, startTime, "", "FGetObject should fail on short timeout", err)
  12593 		return
  12594 	}
  12595 	ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  12596 	defer cancel()
  12597 
  12598 	// Read the data back
  12599 	err = c.FGetObject(ctx, bucketName, objectName, fileName+"-fcontext", minio.GetObjectOptions{})
  12600 	if err != nil {
  12601 		logError(testName, function, args, startTime, "", "FGetObject call shouldn't fail on long timeout", err)
  12602 		return
  12603 	}
  12604 
  12605 	if err = os.Remove(fileName + "-fcontext"); err != nil {
  12606 		logError(testName, function, args, startTime, "", "Remove file failed", err)
  12607 		return
  12608 	}
  12609 
  12610 	successLogger(testName, function, args, startTime).Info()
  12611 }
  12612 
  12613 // Test list object v1 and V2
  12614 func testListObjects() {
  12615 	// initialize logging params
  12616 	startTime := time.Now()
  12617 	testName := getFuncName()
  12618 	function := "ListObjects(bucketName, objectPrefix, recursive, doneCh)"
  12619 	args := map[string]interface{}{
  12620 		"bucketName":   "",
  12621 		"objectPrefix": "",
  12622 		"recursive":    "true",
  12623 	}
  12624 	// Seed random based on current time.
  12625 	rand.Seed(time.Now().Unix())
  12626 
  12627 	// Instantiate new minio client object.
  12628 	c, err := minio.New(os.Getenv(serverEndpoint),
  12629 		&minio.Options{
  12630 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12631 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12632 		})
  12633 	if err != nil {
  12634 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  12635 		return
  12636 	}
  12637 
  12638 	// Enable tracing, write to stderr.
  12639 	// c.TraceOn(os.Stderr)
  12640 
  12641 	// Set user agent.
  12642 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12643 
  12644 	// Generate a new random bucket name.
  12645 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12646 	args["bucketName"] = bucketName
  12647 
  12648 	// Make a new bucket.
  12649 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
  12650 	if err != nil {
  12651 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12652 		return
  12653 	}
  12654 
  12655 	defer cleanupBucket(bucketName, c)
  12656 
  12657 	testObjects := []struct {
  12658 		name         string
  12659 		storageClass string
  12660 	}{
  12661 		// Special characters
  12662 		{"foo bar", "STANDARD"},
  12663 		{"foo-%", "STANDARD"},
  12664 		{"random-object-1", "STANDARD"},
  12665 		{"random-object-2", "REDUCED_REDUNDANCY"},
  12666 	}
  12667 
  12668 	for i, object := range testObjects {
  12669 		bufSize := dataFileMap["datafile-33-kB"]
  12670 		reader := getDataReader("datafile-33-kB")
  12671 		defer reader.Close()
  12672 		_, err = c.PutObject(context.Background(), bucketName, object.name, reader, int64(bufSize),
  12673 			minio.PutObjectOptions{ContentType: "binary/octet-stream", StorageClass: object.storageClass})
  12674 		if err != nil {
  12675 			logError(testName, function, args, startTime, "", fmt.Sprintf("PutObject %d call failed", i+1), err)
  12676 			return
  12677 		}
  12678 	}
  12679 
  12680 	testList := func(listFn func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo, bucket string, opts minio.ListObjectsOptions) {
  12681 		var objCursor int
  12682 
  12683 		// check for object name and storage-class from listing object result
  12684 		for objInfo := range listFn(context.Background(), bucket, opts) {
  12685 			if objInfo.Err != nil {
  12686 				logError(testName, function, args, startTime, "", "ListObjects failed unexpectedly", err)
  12687 				return
  12688 			}
  12689 			if objInfo.Key != testObjects[objCursor].name {
  12690 				logError(testName, function, args, startTime, "", "ListObjects does not return expected object name", err)
  12691 				return
  12692 			}
  12693 			if objInfo.StorageClass != testObjects[objCursor].storageClass {
  12694 				// Ignored as Gateways (Azure/GCS etc) wont return storage class
  12695 				ignoredLog(testName, function, args, startTime, "ListObjects doesn't return expected storage class").Info()
  12696 			}
  12697 			objCursor++
  12698 		}
  12699 
  12700 		if objCursor != len(testObjects) {
  12701 			logError(testName, function, args, startTime, "", "ListObjects returned unexpected number of items", errors.New(""))
  12702 			return
  12703 		}
  12704 	}
  12705 
  12706 	testList(c.ListObjects, bucketName, minio.ListObjectsOptions{Recursive: true, UseV1: true})
  12707 	testList(c.ListObjects, bucketName, minio.ListObjectsOptions{Recursive: true})
  12708 	testList(c.ListObjects, bucketName, minio.ListObjectsOptions{Recursive: true, WithMetadata: true})
  12709 
  12710 	successLogger(testName, function, args, startTime).Info()
  12711 }
  12712 
  12713 // Test deleting multiple objects with object retention set in Governance mode
  12714 func testRemoveObjects() {
  12715 	// initialize logging params
  12716 	startTime := time.Now()
  12717 	testName := getFuncName()
  12718 	function := "RemoveObjects(bucketName, objectsCh, opts)"
  12719 	args := map[string]interface{}{
  12720 		"bucketName":   "",
  12721 		"objectPrefix": "",
  12722 		"recursive":    "true",
  12723 	}
  12724 	// Seed random based on current time.
  12725 	rand.Seed(time.Now().Unix())
  12726 
  12727 	// Instantiate new minio client object.
  12728 	c, err := minio.New(os.Getenv(serverEndpoint),
  12729 		&minio.Options{
  12730 			Creds:  credentials.NewStaticV4(os.Getenv(accessKey), os.Getenv(secretKey), ""),
  12731 			Secure: mustParseBool(os.Getenv(enableHTTPS)),
  12732 		})
  12733 	if err != nil {
  12734 		logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
  12735 		return
  12736 	}
  12737 
  12738 	// Enable tracing, write to stderr.
  12739 	// c.TraceOn(os.Stderr)
  12740 
  12741 	// Set user agent.
  12742 	c.SetAppInfo("MinIO-go-FunctionalTest", "0.1.0")
  12743 
  12744 	// Generate a new random bucket name.
  12745 	bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  12746 	args["bucketName"] = bucketName
  12747 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  12748 	args["objectName"] = objectName
  12749 
  12750 	// Make a new bucket.
  12751 	err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
  12752 	if err != nil {
  12753 		logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  12754 		return
  12755 	}
  12756 
  12757 	bufSize := dataFileMap["datafile-129-MB"]
  12758 	reader := getDataReader("datafile-129-MB")
  12759 	defer reader.Close()
  12760 
  12761 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
  12762 	if err != nil {
  12763 		logError(testName, function, args, startTime, "", "Error uploading object", err)
  12764 		return
  12765 	}
  12766 
  12767 	// Replace with smaller...
  12768 	bufSize = dataFileMap["datafile-10-kB"]
  12769 	reader = getDataReader("datafile-10-kB")
  12770 	defer reader.Close()
  12771 
  12772 	_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
  12773 	if err != nil {
  12774 		logError(testName, function, args, startTime, "", "Error uploading object", err)
  12775 	}
  12776 
  12777 	t := time.Date(2030, time.April, 25, 14, 0, 0, 0, time.UTC)
  12778 	m := minio.RetentionMode(minio.Governance)
  12779 	opts := minio.PutObjectRetentionOptions{
  12780 		GovernanceBypass: false,
  12781 		RetainUntilDate:  &t,
  12782 		Mode:             &m,
  12783 	}
  12784 	err = c.PutObjectRetention(context.Background(), bucketName, objectName, opts)
  12785 	if err != nil {
  12786 		logError(testName, function, args, startTime, "", "Error setting retention", err)
  12787 		return
  12788 	}
  12789 
  12790 	objectsCh := make(chan minio.ObjectInfo)
  12791 	// Send object names that are needed to be removed to objectsCh
  12792 	go func() {
  12793 		defer close(objectsCh)
  12794 		// List all objects from a bucket-name with a matching prefix.
  12795 		for object := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{UseV1: true, Recursive: true}) {
  12796 			if object.Err != nil {
  12797 				logError(testName, function, args, startTime, "", "Error listing objects", object.Err)
  12798 				return
  12799 			}
  12800 			objectsCh <- object
  12801 		}
  12802 	}()
  12803 
  12804 	for rErr := range c.RemoveObjects(context.Background(), bucketName, objectsCh, minio.RemoveObjectsOptions{}) {
  12805 		// Error is expected here because Retention is set on the object
  12806 		// and RemoveObjects is called without Bypass Governance
  12807 		if rErr.Err == nil {
  12808 			logError(testName, function, args, startTime, "", "Expected error during deletion", nil)
  12809 			return
  12810 		}
  12811 	}
  12812 
  12813 	objectsCh1 := make(chan minio.ObjectInfo)
  12814 
  12815 	// Send object names that are needed to be removed to objectsCh
  12816 	go func() {
  12817 		defer close(objectsCh1)
  12818 		// List all objects from a bucket-name with a matching prefix.
  12819 		for object := range c.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{UseV1: true, Recursive: true}) {
  12820 			if object.Err != nil {
  12821 				logError(testName, function, args, startTime, "", "Error listing objects", object.Err)
  12822 				return
  12823 			}
  12824 			objectsCh1 <- object
  12825 		}
  12826 	}()
  12827 
  12828 	opts1 := minio.RemoveObjectsOptions{
  12829 		GovernanceBypass: true,
  12830 	}
  12831 
  12832 	for rErr := range c.RemoveObjects(context.Background(), bucketName, objectsCh1, opts1) {
  12833 		// Error is not expected here because Retention is set on the object
  12834 		// and RemoveObjects is called with Bypass Governance
  12835 		logError(testName, function, args, startTime, "", "Error detected during deletion", rErr.Err)
  12836 		return
  12837 	}
  12838 
  12839 	// Delete all objects and buckets
  12840 	if err = cleanupVersionedBucket(bucketName, c); err != nil {
  12841 		logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
  12842 		return
  12843 	}
  12844 
  12845 	successLogger(testName, function, args, startTime).Info()
  12846 }
  12847 
  12848 // Convert string to bool and always return false if any error
  12849 func mustParseBool(str string) bool {
  12850 	b, err := strconv.ParseBool(str)
  12851 	if err != nil {
  12852 		return false
  12853 	}
  12854 	return b
  12855 }
  12856 
  12857 func main() {
  12858 	// Output to stdout instead of the default stderr
  12859 	log.SetOutput(os.Stdout)
  12860 	// create custom formatter
  12861 	mintFormatter := mintJSONFormatter{}
  12862 	// set custom formatter
  12863 	log.SetFormatter(&mintFormatter)
  12864 	// log Info or above -- success cases are Info level, failures are Fatal level
  12865 	log.SetLevel(log.InfoLevel)
  12866 
  12867 	tls := mustParseBool(os.Getenv(enableHTTPS))
  12868 	kms := mustParseBool(os.Getenv(enableKMS))
  12869 	if os.Getenv(enableKMS) == "" {
  12870 		// Default to KMS tests.
  12871 		kms = true
  12872 	}
  12873 
  12874 	// execute tests
  12875 	if isFullMode() {
  12876 		testMakeBucketErrorV2()
  12877 		testGetObjectClosedTwiceV2()
  12878 		testFPutObjectV2()
  12879 		testMakeBucketRegionsV2()
  12880 		testGetObjectReadSeekFunctionalV2()
  12881 		testGetObjectReadAtFunctionalV2()
  12882 		testGetObjectRanges()
  12883 		testCopyObjectV2()
  12884 		testFunctionalV2()
  12885 		testComposeObjectErrorCasesV2()
  12886 		testCompose10KSourcesV2()
  12887 		testUserMetadataCopyingV2()
  12888 		testPutObjectWithChecksums()
  12889 		testPutMultipartObjectWithChecksums()
  12890 		testPutObject0ByteV2()
  12891 		testPutObjectNoLengthV2()
  12892 		testPutObjectsUnknownV2()
  12893 		testGetObjectContextV2()
  12894 		testFPutObjectContextV2()
  12895 		testFGetObjectContextV2()
  12896 		testPutObjectContextV2()
  12897 		testPutObjectWithVersioning()
  12898 		testMakeBucketError()
  12899 		testMakeBucketRegions()
  12900 		testPutObjectWithMetadata()
  12901 		testPutObjectReadAt()
  12902 		testPutObjectStreaming()
  12903 		testGetObjectSeekEnd()
  12904 		testGetObjectClosedTwice()
  12905 		testGetObjectS3Zip()
  12906 		testRemoveMultipleObjects()
  12907 		testRemoveMultipleObjectsWithResult()
  12908 		testFPutObjectMultipart()
  12909 		testFPutObject()
  12910 		testGetObjectReadSeekFunctional()
  12911 		testGetObjectReadAtFunctional()
  12912 		testGetObjectReadAtWhenEOFWasReached()
  12913 		testPresignedPostPolicy()
  12914 		testCopyObject()
  12915 		testComposeObjectErrorCases()
  12916 		testCompose10KSources()
  12917 		testUserMetadataCopying()
  12918 		testBucketNotification()
  12919 		testFunctional()
  12920 		testGetObjectModified()
  12921 		testPutObjectUploadSeekedObject()
  12922 		testGetObjectContext()
  12923 		testFPutObjectContext()
  12924 		testFGetObjectContext()
  12925 		testGetObjectACLContext()
  12926 		testPutObjectContext()
  12927 		testStorageClassMetadataPutObject()
  12928 		testStorageClassInvalidMetadataPutObject()
  12929 		testStorageClassMetadataCopyObject()
  12930 		testPutObjectWithContentLanguage()
  12931 		testListObjects()
  12932 		testRemoveObjects()
  12933 		testListObjectVersions()
  12934 		testStatObjectWithVersioning()
  12935 		testGetObjectWithVersioning()
  12936 		testCopyObjectWithVersioning()
  12937 		testConcurrentCopyObjectWithVersioning()
  12938 		testComposeObjectWithVersioning()
  12939 		testRemoveObjectWithVersioning()
  12940 		testRemoveObjectsWithVersioning()
  12941 		testObjectTaggingWithVersioning()
  12942 		testTrailingChecksums()
  12943 		testPutObjectWithAutomaticChecksums()
  12944 
  12945 		// SSE-C tests will only work over TLS connection.
  12946 		if tls {
  12947 			testSSECEncryptionPutGet()
  12948 			testSSECEncryptionFPut()
  12949 			testSSECEncryptedGetObjectReadAtFunctional()
  12950 			testSSECEncryptedGetObjectReadSeekFunctional()
  12951 			testEncryptedCopyObjectV2()
  12952 			testEncryptedSSECToSSECCopyObject()
  12953 			testEncryptedSSECToUnencryptedCopyObject()
  12954 			testUnencryptedToSSECCopyObject()
  12955 			testUnencryptedToUnencryptedCopyObject()
  12956 			testEncryptedEmptyObject()
  12957 			testDecryptedCopyObject()
  12958 			testSSECEncryptedToSSECCopyObjectPart()
  12959 			testSSECMultipartEncryptedToSSECCopyObjectPart()
  12960 			testSSECEncryptedToUnencryptedCopyPart()
  12961 			testUnencryptedToSSECCopyObjectPart()
  12962 			testUnencryptedToUnencryptedCopyPart()
  12963 			testEncryptedSSECToSSES3CopyObject()
  12964 			testEncryptedSSES3ToSSECCopyObject()
  12965 			testSSECEncryptedToSSES3CopyObjectPart()
  12966 			testSSES3EncryptedToSSECCopyObjectPart()
  12967 		}
  12968 
  12969 		// KMS tests
  12970 		if kms {
  12971 			testSSES3EncryptionPutGet()
  12972 			testSSES3EncryptionFPut()
  12973 			testSSES3EncryptedGetObjectReadAtFunctional()
  12974 			testSSES3EncryptedGetObjectReadSeekFunctional()
  12975 			testEncryptedSSES3ToSSES3CopyObject()
  12976 			testEncryptedSSES3ToUnencryptedCopyObject()
  12977 			testUnencryptedToSSES3CopyObject()
  12978 			testUnencryptedToSSES3CopyObjectPart()
  12979 			testSSES3EncryptedToUnencryptedCopyPart()
  12980 			testSSES3EncryptedToSSES3CopyObjectPart()
  12981 		}
  12982 	} else {
  12983 		testFunctional()
  12984 		testFunctionalV2()
  12985 	}
  12986 }