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 }