github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/suite_test.go (about)

     1  // Copyright (c) 2015-2024 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/md5"
    23  	"crypto/tls"
    24  	"encoding/json"
    25  	"fmt"
    26  	"io"
    27  	"log"
    28  	"math/rand"
    29  	"net/http"
    30  	"os"
    31  	"os/exec"
    32  	"runtime"
    33  	"runtime/debug"
    34  	"strconv"
    35  	"strings"
    36  	"testing"
    37  	"time"
    38  
    39  	"github.com/google/uuid"
    40  	"github.com/minio/mc/pkg/disk"
    41  )
    42  
    43  // RUN: go test -v ./... -run Test_FullSuite
    44  func Test_FullSuite(t *testing.T) {
    45  	if os.Getenv("MC_TEST_RUN_FULL_SUITE") != "true" {
    46  		return
    47  	}
    48  
    49  	defer func() {
    50  		r := recover()
    51  		if r != nil {
    52  			log.Println(r, string(debug.Stack()))
    53  		}
    54  
    55  		postRunCleanup(t)
    56  	}()
    57  
    58  	preflightCheck(t)
    59  	// initializeTestSuite builds the mc client and creates local files which are used for testing
    60  	initializeTestSuite(t)
    61  
    62  	// Tests within this function depend on one another
    63  	testsThatDependOnOneAnother(t)
    64  
    65  	// Alias tests
    66  	AddALIASWithError(t)
    67  
    68  	// Basic admin user tests
    69  	AdminUserFunctionalTest(t)
    70  
    71  	// Share upload/download
    72  	ShareURLUploadTest(t)
    73  	ShareURLDownloadTest(t)
    74  
    75  	// TODO .. for some reason the connection is randomly
    76  	// reset when running curl.
    77  	// ShareURLUploadErrorTests(t)
    78  
    79  	// Bucket Error Tests
    80  	CreateBucketUsingInvalidSymbols(t)
    81  	RemoveBucketWithNameTooLong(t)
    82  	RemoveBucketThatDoesNotExist(t)
    83  
    84  	// MC_TEST_ENABLE_HTTPS=true
    85  	// needs to be set in order to run these tests
    86  	if protocol == "https://" {
    87  		PutObjectWithSSEC(t)
    88  		PutObjectWithSSECPartialPrefixMatch(t)
    89  		PutObjectWithSSECMultipart(t)
    90  		PutObjectWithSSECInvalidKeys(t)
    91  		GetObjectWithSSEC(t)
    92  		GetObjectWithSSECWithoutKey(t)
    93  		CatObjectWithSSEC(t)
    94  		CatObjectWithSSECWithoutKey(t)
    95  		CopyObjectWithSSECToNewBucketWithNewKey(t)
    96  		MirrorTempDirectoryUsingSSEC(t)
    97  		RemoveObjectWithSSEC(t)
    98  	} else {
    99  		PutObjectErrorWithSSECOverHTTP(t)
   100  	}
   101  
   102  	// MC_TEST_KMS_KEY=[KEY_NAME]
   103  	// needs to be set in order to run these tests
   104  	if sseKMSKeyName != "" {
   105  		VerifyKMSKey(t)
   106  		PutObjectWithSSEKMS(t)
   107  		PutObjectWithSSEKMSPartialPrefixMatch(t)
   108  		PutObjectWithSSEKMSMultipart(t)
   109  		PutObjectWithSSEKMSInvalidKeys(t)
   110  		GetObjectWithSSEKMS(t)
   111  		CatObjectWithSSEKMS(t)
   112  		CopyObjectWithSSEKMSToNewBucket(t)
   113  		MirrorTempDirectoryUsingSSEKMS(t)
   114  		RemoveObjectWithSSEKMS(t)
   115  
   116  		// Error tests
   117  		CopyObjectWithSSEKMSWithOverLappingKeys(t)
   118  	}
   119  
   120  	// MC_TEST_ENABLE_SSE_S3=true
   121  	// needs to be set to in order to run these tests.
   122  	if sseS3Enabled {
   123  		PutObjectWithSSES3(t)
   124  		PutObjectWithSSES3PartialPrefixMatch(t)
   125  		PutObjectWithSSES3Multipart(t)
   126  		GetObjectWithSSES3(t)
   127  		CatObjectWithSSES3(t)
   128  		CopyObjectWithSSES3ToNewBucket(t)
   129  		MirrorTempDirectoryUsingSSES3(t)
   130  	}
   131  
   132  	if protocol == "https://" && sseKMSKeyName != "" {
   133  		CopyObjectWithSSEKMSToNewBucketWithSSEC(t)
   134  	}
   135  
   136  	// (DEPRECATED CLI PARAMETERS)
   137  	if includeDeprecatedMethods {
   138  		fmt.Println("No deprecated methods implemented")
   139  	}
   140  }
   141  
   142  func testsThatDependOnOneAnother(t *testing.T) {
   143  	CreateFileBundle()
   144  	// uploadAllFiles uploads all files in FileMap to MainTestBucket
   145  	uploadAllFiles(t)
   146  	// LSObjects saves the output of LS inside *testFile in FileMap
   147  	LSObjects(t)
   148  	// StatObjecsts saves the output of Stat inside *testFile in FileMap
   149  	StatObjects(t)
   150  	// ValidateFileMetaDataPostUpload validates the output of LS and Stat
   151  	ValidateFileMetaData(t)
   152  
   153  	// DU tests
   154  	DUBucket(t)
   155  
   156  	// Std in/out .. pipe/cat
   157  	CatObjectToStdIn(t)
   158  	CatObjectFromStdin(t)
   159  
   160  	// Preserve attributes
   161  	PutObjectPreserveAttributes(t)
   162  
   163  	// Mirror
   164  	MirrorTempDirectoryStorageClassReducedRedundancy(t)
   165  	MirrorTempDirectory(t)
   166  
   167  	// General object tests
   168  	FindObjects(t)
   169  	FindObjectsUsingName(t)
   170  	FindObjectsUsingNameAndFilteringForTxtType(t)
   171  	FindObjectsLargerThan64Mebibytes(t)
   172  	FindObjectsSmallerThan64Mebibytes(t)
   173  	FindObjectsOlderThan1d(t)
   174  	FindObjectsNewerThen1d(t)
   175  	GetObjectsAndCompareMD5(t)
   176  }
   177  
   178  type TestUser struct {
   179  	Username string
   180  	Password string
   181  }
   182  
   183  var (
   184  	oneMBSlice               [1048576]byte // 1x Mebibyte
   185  	defaultAlias             = "mintest"
   186  	fileMap                  = make(map[string]*testFile)
   187  	randomLargeString        = "lksdjfljsdklfjklsdjfklksjdf;lsjdk;fjks;djflsdlfkjskldjfklkljsdfljsldkfjklsjdfkljsdklfjklsdjflksjdlfjsdjflsjdflsldfjlsjdflksjdflkjslkdjflksfdj"
   188  	jsonFlag                 = "--json"
   189  	insecureFlag             = "--insecure"
   190  	jsonOutput               = true
   191  	printRawOut              = false
   192  	skipBuild                = false
   193  	mcCmd                    = ".././mc"
   194  	preCmdParameters         = make([]string, 0)
   195  	buildPath                = "../."
   196  	metaPrefix               = "X-Amz-Meta-"
   197  	includeDeprecatedMethods = false
   198  
   199  	serverEndpoint = "127.0.0.1:9000"
   200  	acessKey       = "minioadmin"
   201  	secretKey      = "minioadmin"
   202  	protocol       = "http://"
   203  	skipInsecure   = true
   204  	tempDir        = ""
   205  	mainTestBucket string
   206  	sseTestBucket  string
   207  	bucketList     = make([]string, 0)
   208  	userList       = make(map[string]TestUser, 0)
   209  
   210  	// KMS
   211  	sseBaseEncodedKey        = "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA"
   212  	invalidSSEBaseEncodedKey = "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5"
   213  	sseBaseEncodedKey2       = "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5YWE"
   214  	sseKMSKeyName            = ""
   215  	sseInvalidKmsKeyName     = ""
   216  	sseS3Enabled             = false
   217  
   218  	curlPath      = "/usb/bin/curl"
   219  	HTTPClient    *http.Client
   220  	failIndicator = "!! FAIL !! _______________________ !! FAIL !! _______________________ !! FAIL !!"
   221  )
   222  
   223  func openFileAndGetMd5Sum(path string) (md5s string, err error) {
   224  	f, err := os.Open(path)
   225  	if err != nil {
   226  		return "", err
   227  	}
   228  	defer f.Close()
   229  	fb, err := io.ReadAll(f)
   230  	if err != nil {
   231  		return "", err
   232  	}
   233  	md5s = GetMD5Sum(fb)
   234  	return
   235  }
   236  
   237  func GetMBSizeInBytes(MB int) int64 {
   238  	return int64(MB * len(oneMBSlice))
   239  }
   240  
   241  func initializeTestSuite(t *testing.T) {
   242  	shouldSkipBuild := os.Getenv("MC_TEST_SKIP_BUILD")
   243  	skipBuild, _ = strconv.ParseBool(shouldSkipBuild)
   244  	fmt.Println("SKIP BUILD:", skipBuild)
   245  	if !skipBuild {
   246  		err := BuildCLI()
   247  		if err != nil {
   248  			os.Exit(1)
   249  		}
   250  	}
   251  	envBuildPath := os.Getenv("MC_TEST_BUILD_PATH")
   252  	if envBuildPath != "" {
   253  		buildPath = envBuildPath
   254  	}
   255  
   256  	envALIAS := os.Getenv("MC_TEST_ALIAS")
   257  	if envALIAS != "" {
   258  		defaultAlias = envALIAS
   259  	}
   260  
   261  	envSecretKey := os.Getenv("MC_TEST_SECRET_KEY")
   262  	if envSecretKey != "" {
   263  		secretKey = envSecretKey
   264  	}
   265  
   266  	envAccessKey := os.Getenv("MC_TEST_ACCESS_KEY")
   267  	if envAccessKey != "" {
   268  		acessKey = envAccessKey
   269  	}
   270  
   271  	envServerEndpoint := os.Getenv("MC_TEST_SERVER_ENDPOINT")
   272  	if envServerEndpoint != "" {
   273  		serverEndpoint = envServerEndpoint
   274  	}
   275  
   276  	envIncludeDeprecated := os.Getenv("MC_TEST_INCLUDE_DEPRECATED")
   277  	includeDeprecatedMethods, _ = strconv.ParseBool(envIncludeDeprecated)
   278  
   279  	envKmsKey := os.Getenv("MC_TEST_KMS_KEY")
   280  	if envKmsKey != "" {
   281  		sseKMSKeyName = envKmsKey
   282  	}
   283  
   284  	envSSES3Enabled := os.Getenv("MC_TEST_ENABLE_SSE_S3")
   285  	if envSSES3Enabled != "" {
   286  		sseS3Enabled, _ = strconv.ParseBool(envSSES3Enabled)
   287  	}
   288  
   289  	envSkipInsecure := os.Getenv("MC_TEST_SKIP_INSECURE")
   290  	if envSkipInsecure != "" {
   291  		skipInsecure, _ = strconv.ParseBool(envSkipInsecure)
   292  	}
   293  
   294  	envEnableHTTP := os.Getenv("MC_TEST_ENABLE_HTTPS")
   295  	EnableHTTPS, _ := strconv.ParseBool(envEnableHTTP)
   296  	if EnableHTTPS {
   297  		protocol = "https://"
   298  	}
   299  
   300  	envCMD := os.Getenv("MC_TEST_BINARY_PATH")
   301  	if envCMD != "" {
   302  		mcCmd = envCMD
   303  	}
   304  
   305  	var err error
   306  	tempDir, err = os.MkdirTemp("", "test-")
   307  	if err != nil {
   308  		log.Println(err)
   309  		os.Exit(1)
   310  	}
   311  
   312  	for i := 0; i < len(oneMBSlice); i++ {
   313  		oneMBSlice[i] = byte(rand.Intn(250))
   314  	}
   315  
   316  	for i := 0; i < 10; i++ {
   317  		tmpNameMap["aaa"+strconv.Itoa(i)] = false
   318  	}
   319  	for i := 0; i < 10; i++ {
   320  		tmpNameMap["bbb"+strconv.Itoa(i)] = false
   321  	}
   322  	for i := 0; i < 10; i++ {
   323  		tmpNameMap["ccc"+strconv.Itoa(i)] = false
   324  	}
   325  	for i := 0; i < 10; i++ {
   326  		tmpNameMap["ddd"+strconv.Itoa(i)] = false
   327  	}
   328  
   329  	HTTPClient = &http.Client{
   330  		Transport: &http.Transport{
   331  			TLSClientConfig: &tls.Config{InsecureSkipVerify: skipInsecure},
   332  		},
   333  	}
   334  
   335  	if jsonOutput {
   336  		preCmdParameters = append(preCmdParameters, jsonFlag)
   337  	}
   338  
   339  	if skipInsecure {
   340  		preCmdParameters = append(preCmdParameters, insecureFlag)
   341  	}
   342  
   343  	CreateTestUsers()
   344  
   345  	_, err = RunMC(
   346  		"alias",
   347  		"set",
   348  		defaultAlias,
   349  		protocol+serverEndpoint,
   350  		acessKey,
   351  		secretKey,
   352  	)
   353  	fatalIfError(err, t)
   354  
   355  	out, err := RunMC("--version")
   356  	fatalIfError(err, t)
   357  	fmt.Println(out)
   358  
   359  	preRunCleanup()
   360  
   361  	mainTestBucket = CreateBucket(t)
   362  	sseTestBucket = CreateBucket(t)
   363  }
   364  
   365  func preflightCheck(t *testing.T) {
   366  	out, err := exec.Command("which", "curl").Output()
   367  	fatalIfError(err, t)
   368  	if len(out) == 0 {
   369  		fatalMsgOnly("No curl found, output from 'which curl': "+string(out), t)
   370  	}
   371  	curlPath = string(out)
   372  }
   373  
   374  func CreateTestUsers() {
   375  	userList["user1"] = TestUser{
   376  		Username: "user1",
   377  		Password: "user1-password",
   378  	}
   379  	userList["user2"] = TestUser{
   380  		Username: "user2",
   381  		Password: "user2-password",
   382  	}
   383  	userList["user3"] = TestUser{
   384  		Username: "user3",
   385  		Password: "user3-password",
   386  	}
   387  }
   388  
   389  func CreateFileBundle() {
   390  	createFile(newTestFile{
   391  		tag:          "0M",
   392  		prefix:       "",
   393  		extension:    ".jpg",
   394  		storageClass: "",
   395  		sizeInMBS:    0,
   396  		tags:         map[string]string{"name": "0M"},
   397  		// uploadShouldFail:   false,
   398  		addToGlobalFileMap: true,
   399  	})
   400  	createFile(newTestFile{
   401  		tag:          "1M",
   402  		prefix:       "",
   403  		extension:    ".txt",
   404  		storageClass: "REDUCED_REDUNDANCY",
   405  		sizeInMBS:    1,
   406  		metaData:     map[string]string{"name": "1M"},
   407  		tags:         map[string]string{"tag1": "1M-tag"},
   408  		// uploadShouldFail:   false,
   409  		addToGlobalFileMap: true,
   410  	})
   411  	createFile(newTestFile{
   412  		tag:          "2M",
   413  		prefix:       "LVL1",
   414  		extension:    ".jpg",
   415  		storageClass: "REDUCED_REDUNDANCY",
   416  		sizeInMBS:    2,
   417  		metaData:     map[string]string{"name": "2M"},
   418  		// uploadShouldFail:   false,
   419  		addToGlobalFileMap: true,
   420  	})
   421  	createFile(newTestFile{
   422  		tag:          "3M",
   423  		prefix:       "LVL1/LVL2",
   424  		extension:    ".png",
   425  		storageClass: "",
   426  		sizeInMBS:    3,
   427  		metaData:     map[string]string{"name": "3M"},
   428  		// uploadShouldFail:   false,
   429  		addToGlobalFileMap: true,
   430  	})
   431  	createFile(newTestFile{
   432  		tag:          "65M",
   433  		prefix:       "LVL1/LVL2/LVL3",
   434  		extension:    ".exe",
   435  		storageClass: "",
   436  		sizeInMBS:    65,
   437  		metaData:     map[string]string{"name": "65M", "tag1": "value1"},
   438  		// uploadShouldFail:   false,
   439  		addToGlobalFileMap: true,
   440  	})
   441  }
   442  
   443  var tmpNameMap = make(map[string]bool)
   444  
   445  func GetRandomName() string {
   446  	for i := range tmpNameMap {
   447  		if tmpNameMap[i] == false {
   448  			tmpNameMap[i] = true
   449  			return i
   450  		}
   451  	}
   452  	return uuid.NewString()
   453  }
   454  
   455  func CreateBucket(t *testing.T) (bucketPath string) {
   456  	bucketName := "test-" + GetRandomName()
   457  	bucketPath = defaultAlias + "/" + bucketName
   458  	out, err := RunMC("mb", bucketPath)
   459  	if err != nil {
   460  		t.Fatalf("Unable to create bucket (%s) err: %s", bucketPath, out)
   461  		return
   462  	}
   463  	bucketList = append(bucketList, bucketPath)
   464  	out, err = RunMC("stat", defaultAlias+"/"+bucketName)
   465  	if err != nil {
   466  		t.Fatalf("Unable to ls stat (%s) err: %s", defaultAlias+"/"+bucketName, out)
   467  		return
   468  	}
   469  	if !strings.Contains(out, bucketName) {
   470  		t.Fatalf("stat output does not contain bucket name (%s)", bucketName)
   471  	}
   472  	return
   473  }
   474  
   475  func AddALIASWithError(t *testing.T) {
   476  	out, err := RunMC(
   477  		"alias",
   478  		"set",
   479  		defaultAlias,
   480  		protocol+serverEndpoint,
   481  		acessKey,
   482  		"random-invalid-secret-that-will-not-work",
   483  	)
   484  	fatalIfNoErrorWMsg(err, out, t)
   485  }
   486  
   487  func AdminUserFunctionalTest(t *testing.T) {
   488  	user1Bucket := CreateBucket(t)
   489  
   490  	user1File := createFile(newTestFile{
   491  		addToGlobalFileMap: false,
   492  		tag:                "user1",
   493  		sizeInMBS:          1,
   494  	})
   495  
   496  	out, err := RunMC(
   497  		"admin",
   498  		"user",
   499  		"add",
   500  		defaultAlias,
   501  		userList["user1"].Username,
   502  		userList["user1"].Password,
   503  	)
   504  	fatalIfErrorWMsg(err, out, t)
   505  
   506  	out, err = RunMC(
   507  		"admin",
   508  		"user",
   509  		"list",
   510  		defaultAlias,
   511  	)
   512  	fatalIfErrorWMsg(err, out, t)
   513  	userOutput, err := parseUserMessageListOutput(out)
   514  	fatalIfErrorWMsg(err, out, t)
   515  
   516  	user1found := false
   517  	for i := range userOutput {
   518  		if userOutput[i].AccessKey == userList["user1"].Username {
   519  			user1found = true
   520  		}
   521  	}
   522  
   523  	if !user1found {
   524  		fatalMsgOnly(fmt.Sprintf("did not find user %s when running admin user list --json", userList["user1"].Username), t)
   525  	}
   526  
   527  	out, err = RunMC(
   528  		"admin",
   529  		"policy",
   530  		"attach",
   531  		defaultAlias,
   532  		"readwrite",
   533  		"--user="+userList["user1"].Username,
   534  	)
   535  	fatalIfErrorWMsg(err, out, t)
   536  
   537  	out, err = RunMC(
   538  		"alias",
   539  		"set",
   540  		userList["user1"].Username,
   541  		protocol+serverEndpoint,
   542  		userList["user1"].Username,
   543  		userList["user1"].Password,
   544  	)
   545  	fatalIfErrorWMsg(err, out, t)
   546  
   547  	out, err = RunMC(
   548  		"cp",
   549  		user1File.diskFile.Name(),
   550  		user1Bucket+"/"+user1File.fileNameWithoutPath,
   551  	)
   552  	fatalIfErrorWMsg(err, out, t)
   553  }
   554  
   555  func ShareURLUploadErrorTests(t *testing.T) {
   556  	shareURLErrorBucket := CreateBucket(t)
   557  
   558  	file := createFile(newTestFile{
   559  		addToGlobalFileMap: false,
   560  		tag:                "presigned-error",
   561  		sizeInMBS:          1,
   562  	})
   563  
   564  	out, err := RunMC(
   565  		"share",
   566  		"upload",
   567  		shareURLErrorBucket+"/"+file.fileNameWithoutPath,
   568  	)
   569  	fatalIfErrorWMsg(err, out, t)
   570  
   571  	shareMsg, err := parseShareMessageFromJSONOutput(out)
   572  	fatalIfErrorWMsg(err, out, t)
   573  
   574  	finalURL := strings.Replace(shareMsg.ShareURL, "<FILE>", file.diskFile.Name(), -1)
   575  	splitCommand := strings.Split(finalURL, " ")
   576  
   577  	if skipInsecure {
   578  		splitCommand = append(splitCommand, "--insecure")
   579  	}
   580  
   581  	bucketOnly := strings.Replace(shareURLErrorBucket, defaultAlias+"/", "", -1)
   582  
   583  	// Modify base url bucket path
   584  	newCmd := make([]string, len(splitCommand))
   585  	copy(newCmd, splitCommand)
   586  	newCmd[1] = strings.Replace(newCmd[1], bucketOnly, "fake-bucket-name", -1)
   587  	out, _ = RunCommand(newCmd[0], newCmd[1:]...)
   588  	curlFatalIfNoErrorTag(out, t)
   589  
   590  	// Modify -F key=X
   591  	newCmd = make([]string, len(splitCommand))
   592  	copy(newCmd, splitCommand)
   593  	for i := range newCmd {
   594  		if strings.HasPrefix(newCmd[i], "key=") {
   595  			newCmd[i] = "key=fake-object-name"
   596  			break
   597  		}
   598  	}
   599  	out, _ = RunCommand(newCmd[0], newCmd[1:]...)
   600  	curlFatalIfNoErrorTag(out, t)
   601  }
   602  
   603  func ShareURLUploadTest(t *testing.T) {
   604  	ShareURLTestBucket := CreateBucket(t)
   605  
   606  	file := createFile(newTestFile{
   607  		addToGlobalFileMap: true,
   608  		tag:                "presigned-upload",
   609  		sizeInMBS:          1,
   610  	})
   611  
   612  	out, err := RunMC(
   613  		"share",
   614  		"upload",
   615  		ShareURLTestBucket+"/"+file.fileNameWithoutPath,
   616  	)
   617  	fatalIfErrorWMsg(err, out, t)
   618  
   619  	shareMsg, err := parseShareMessageFromJSONOutput(out)
   620  	fatalIfErrorWMsg(err, out, t)
   621  
   622  	finalURL := strings.Replace(shareMsg.ShareURL, "<FILE>", file.diskFile.Name(), -1)
   623  	splitCommand := strings.Split(finalURL, " ")
   624  
   625  	if skipInsecure {
   626  		splitCommand = append(splitCommand, "--insecure")
   627  	}
   628  
   629  	_, err = exec.Command(splitCommand[0], splitCommand[1:]...).CombinedOutput()
   630  	fatalIfErrorWMsg(err, out, t)
   631  
   632  	out, err = RunMC(
   633  		"stat",
   634  		ShareURLTestBucket+"/"+file.fileNameWithoutPath,
   635  	)
   636  	fatalIfErrorWMsg(err, out, t)
   637  
   638  	statMsg, err := parseStatSingleObjectJSONOutput(out)
   639  	fatalIfError(err, t)
   640  
   641  	if statMsg.ETag != file.md5Sum {
   642  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got md5sum (%s)", file.md5Sum, file.md5Sum), t)
   643  	}
   644  }
   645  
   646  func ShareURLDownloadTest(t *testing.T) {
   647  	ShareURLTestBucket := CreateBucket(t)
   648  	file := createFile(newTestFile{
   649  		addToGlobalFileMap: true,
   650  		tag:                "presigned-download",
   651  		sizeInMBS:          1,
   652  	})
   653  
   654  	out, err := RunMC(
   655  		"cp",
   656  		file.diskFile.Name(),
   657  		ShareURLTestBucket+"/"+file.fileNameWithoutPath,
   658  	)
   659  	fatalIfErrorWMsg(err, out, t)
   660  
   661  	out, err = RunMC(
   662  		"share",
   663  		"download",
   664  		ShareURLTestBucket+"/"+file.fileNameWithoutPath,
   665  	)
   666  	fatalIfErrorWMsg(err, out, t)
   667  
   668  	shareMsg, err := parseShareMessageFromJSONOutput(out)
   669  	fatalIfErrorWMsg(err, out, t)
   670  
   671  	resp, err := HTTPClient.Get(shareMsg.ShareURL)
   672  	fatalIfError(err, t)
   673  
   674  	downloadedFile, err := io.ReadAll(resp.Body)
   675  	fatalIfError(err, t)
   676  
   677  	md5sum := GetMD5Sum(downloadedFile)
   678  	if md5sum != file.md5Sum {
   679  		fatalMsgOnly(
   680  			fmt.Sprintf("expecting md5sum (%s) but got md5sum (%s)", file.md5Sum, md5sum),
   681  			t,
   682  		)
   683  	}
   684  }
   685  
   686  func PutObjectPreserveAttributes(t *testing.T) {
   687  	AttrTestBucket := CreateBucket(t)
   688  	file := fileMap["1M"]
   689  	out, err := RunMC(
   690  		"cp",
   691  		"-a",
   692  		file.diskFile.Name(),
   693  		AttrTestBucket+"/"+file.fileNameWithoutPath,
   694  	)
   695  	fatalIfErrorWMsg(err, out, t)
   696  
   697  	out, err = RunMC(
   698  		"stat",
   699  		AttrTestBucket+"/"+file.fileNameWithPrefix,
   700  	)
   701  	fatalIfError(err, t)
   702  
   703  	stats, err := parseStatSingleObjectJSONOutput(out)
   704  	fatalIfError(err, t)
   705  
   706  	attr, err := disk.GetFileSystemAttrs(file.diskFile.Name())
   707  	fatalIfError(err, t)
   708  	if attr != stats.Metadata["X-Amz-Meta-Mc-Attrs"] {
   709  		fatalMsgOnly(fmt.Sprintf("expecting file attributes (%s) but got file attributes (%s)", attr, stats.Metadata["X-Amz-Meta-Mc-Attrs"]), t)
   710  	}
   711  }
   712  
   713  func MirrorTempDirectoryStorageClassReducedRedundancy(t *testing.T) {
   714  	MirrorBucket := CreateBucket(t)
   715  	out, err := RunMC(
   716  		"mirror",
   717  		"--storage-class", "REDUCED_REDUNDANCY",
   718  		tempDir,
   719  		MirrorBucket,
   720  	)
   721  	fatalIfErrorWMsg(err, out, t)
   722  
   723  	out, err = RunMC("ls", "-r", MirrorBucket)
   724  	fatalIfError(err, t)
   725  
   726  	fileList, err := parseLSJSONOutput(out)
   727  	fatalIfError(err, t)
   728  
   729  	for i, f := range fileMap {
   730  		fileFound := false
   731  
   732  		for _, o := range fileList {
   733  			if o.Key == f.fileNameWithoutPath {
   734  				fileMap[i].MinioLS = o
   735  				fileFound = true
   736  			}
   737  		}
   738  
   739  		if !fileFound {
   740  			t.Fatalf("File was not uploaded: %s", f.fileNameWithPrefix)
   741  		}
   742  	}
   743  }
   744  
   745  func MirrorTempDirectory(t *testing.T) {
   746  	MirrorBucket := CreateBucket(t)
   747  
   748  	out, err := RunMC(
   749  		"mirror",
   750  		tempDir,
   751  		MirrorBucket,
   752  	)
   753  	fatalIfErrorWMsg(err, out, t)
   754  
   755  	out, err = RunMC("ls", "-r", MirrorBucket)
   756  	fatalIfError(err, t)
   757  
   758  	fileList, err := parseLSJSONOutput(out)
   759  	fatalIfError(err, t)
   760  
   761  	for i, f := range fileMap {
   762  		fileFound := false
   763  
   764  		for _, o := range fileList {
   765  			if o.Key == f.fileNameWithoutPath {
   766  				fileMap[i].MinioLS = o
   767  				fileFound = true
   768  			}
   769  		}
   770  
   771  		if !fileFound {
   772  			t.Fatalf("File was not uploaded: %s", f.fileNameWithPrefix)
   773  		}
   774  	}
   775  }
   776  
   777  func CatObjectFromStdin(t *testing.T) {
   778  	objectName := "pipe-test-object"
   779  	CatEchoBucket := CreateBucket(t)
   780  
   781  	file := fileMap["1M"]
   782  
   783  	cmdCAT := exec.Command(
   784  		"cat",
   785  		file.diskFile.Name(),
   786  	)
   787  
   788  	p := []string{
   789  		"pipe",
   790  		CatEchoBucket + "/" + objectName,
   791  	}
   792  	if skipInsecure {
   793  		p = append(p, "--insecure")
   794  	}
   795  
   796  	cmdMC := exec.Command(mcCmd, p...)
   797  
   798  	r, w := io.Pipe()
   799  	defer r.Close()
   800  	defer w.Close()
   801  
   802  	cmdCAT.Stdout = w
   803  	cmdMC.Stdin = r
   804  
   805  	err := cmdMC.Start()
   806  	fatalIfError(err, t)
   807  	err = cmdCAT.Start()
   808  	fatalIfError(err, t)
   809  
   810  	err = cmdCAT.Wait()
   811  	fatalIfError(err, t)
   812  	w.Close()
   813  	err = cmdMC.Wait()
   814  	fatalIfError(err, t)
   815  	r.Close()
   816  
   817  	outB, err := RunMC(
   818  		"cat",
   819  		CatEchoBucket+"/"+objectName,
   820  	)
   821  	fatalIfErrorWMsg(err, outB, t)
   822  
   823  	md5SumCat := GetMD5Sum([]byte(outB))
   824  	if file.md5Sum != md5SumCat {
   825  		fatalMsgOnly(
   826  			fmt.Sprintf("expecting md5sum (%s) but got md5sum (%s)", file.md5Sum, md5SumCat),
   827  			t,
   828  		)
   829  	}
   830  }
   831  
   832  func CatObjectToStdIn(t *testing.T) {
   833  	file := fileMap["1M"]
   834  	out, err := RunMC(
   835  		"cat",
   836  		mainTestBucket+"/"+file.fileNameWithoutPath,
   837  	)
   838  	fatalIfErrorWMsg(err, out, t)
   839  	md5Sum := GetMD5Sum([]byte(out))
   840  	if md5Sum != file.md5Sum {
   841  		fatalMsgOnly(
   842  			fmt.Sprintf("expecting md5sum (%s) but got md5sum (%s)", file.md5Sum, md5Sum),
   843  			t,
   844  		)
   845  	}
   846  }
   847  
   848  func VerifyKMSKey(t *testing.T) {
   849  	out, err := RunMC(
   850  		"admin",
   851  		"kms",
   852  		"key",
   853  		"list",
   854  		defaultAlias,
   855  	)
   856  	fatalIfError(err, t)
   857  	keyMsg := new(kmsKeysMsg)
   858  	err = json.Unmarshal([]byte(out), keyMsg)
   859  	fatalIfError(err, t)
   860  	sseInvalidKmsKeyName = uuid.NewString()
   861  	found := false
   862  	invalidKeyFound := false
   863  	for _, v := range keyMsg.Keys {
   864  		if v == sseKMSKeyName {
   865  			found = true
   866  			break
   867  		}
   868  		if v == sseInvalidKmsKeyName {
   869  			invalidKeyFound = true
   870  		}
   871  	}
   872  	if !found {
   873  		fatalMsgOnly(fmt.Sprintf("expected to find kms key %s but got these keys: %v", sseKMSKeyName, keyMsg.Keys), t)
   874  	}
   875  	if invalidKeyFound {
   876  		fatalMsgOnly("tried to create invalid uuid kms key but for some reason it overlapped with an already existing key", t)
   877  	}
   878  }
   879  
   880  func PutObjectWithSSEKMSPartialPrefixMatch(t *testing.T) {
   881  	file := createFile(newTestFile{
   882  		addToGlobalFileMap: false,
   883  		tag:                "encput-kms-prefix-test",
   884  		sizeInMBS:          1,
   885  	})
   886  
   887  	out, err := RunMC(
   888  		"cp",
   889  		"--enc-kms",
   890  		sseTestBucket+"/"+file.fileNameWithoutPath+"="+sseKMSKeyName,
   891  		file.diskFile.Name(),
   892  		sseTestBucket,
   893  	)
   894  	fatalIfErrorWMsg(err, out, t)
   895  }
   896  
   897  func PutObjectWithSSEKMS(t *testing.T) {
   898  	file := createFile(newTestFile{
   899  		addToGlobalFileMap: false,
   900  		tag:                "encput-kms",
   901  		sizeInMBS:          1,
   902  	})
   903  
   904  	out, err := RunMC(
   905  		"cp",
   906  		"--enc-kms",
   907  		sseTestBucket+"="+sseKMSKeyName,
   908  		file.diskFile.Name(),
   909  		sseTestBucket+"/"+file.fileNameWithoutPath,
   910  	)
   911  	fatalIfErrorWMsg(err, out, t)
   912  }
   913  
   914  func PutObjectWithSSEKMSMultipart(t *testing.T) {
   915  	file := createFile(newTestFile{
   916  		addToGlobalFileMap: false,
   917  		tag:                "encmultiput-kms",
   918  		sizeInMBS:          68,
   919  	})
   920  
   921  	out, err := RunMC(
   922  		"cp",
   923  		"--enc-kms",
   924  		sseTestBucket+"="+sseKMSKeyName,
   925  		file.diskFile.Name(),
   926  		sseTestBucket+"/"+file.fileNameWithoutPath,
   927  	)
   928  	fatalIfErrorWMsg(err, out, t)
   929  }
   930  
   931  func PutObjectWithSSEKMSInvalidKeys(t *testing.T) {
   932  	file := createFile(newTestFile{
   933  		addToGlobalFileMap: false,
   934  		tag:                "encerror-kms",
   935  		sizeInMBS:          1,
   936  	})
   937  
   938  	out, err := RunMC(
   939  		"cp",
   940  		"--enc-kms="+sseTestBucket+"="+sseInvalidKmsKeyName,
   941  		file.diskFile.Name(),
   942  		sseTestBucket+"/"+file.fileNameWithoutPath,
   943  	)
   944  	fatalIfNoErrorWMsg(err, out, t)
   945  }
   946  
   947  func GetObjectWithSSES3(t *testing.T) {
   948  	file := createFile(newTestFile{
   949  		addToGlobalFileMap: false,
   950  		tag:                "encget-s3",
   951  		sizeInMBS:          1,
   952  	})
   953  
   954  	out, err := RunMC(
   955  		"cp",
   956  		"--enc-s3="+sseTestBucket,
   957  		file.diskFile.Name(),
   958  		sseTestBucket+"/"+file.fileNameWithoutPath,
   959  	)
   960  	fatalIfErrorWMsg(err, out, t)
   961  
   962  	out, err = RunMC(
   963  		"cp",
   964  		sseTestBucket+"/"+file.fileNameWithoutPath,
   965  		file.diskFile.Name()+".download",
   966  	)
   967  	fatalIfErrorWMsg(err, out, t)
   968  
   969  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
   970  	fatalIfError(err, t)
   971  	if md5s != file.md5Sum {
   972  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
   973  	}
   974  }
   975  
   976  func CatObjectWithSSES3(t *testing.T) {
   977  	file := createFile(newTestFile{
   978  		addToGlobalFileMap: false,
   979  		tag:                "enccat-s3",
   980  		sizeInMBS:          1,
   981  	})
   982  
   983  	out, err := RunMC(
   984  		"cp",
   985  		"--enc-s3="+sseTestBucket,
   986  		file.diskFile.Name(),
   987  		sseTestBucket+"/"+file.fileNameWithoutPath,
   988  	)
   989  	fatalIfErrorWMsg(err, out, t)
   990  
   991  	out, err = RunMC(
   992  		"cat",
   993  		sseTestBucket+"/"+file.fileNameWithoutPath,
   994  	)
   995  	fatalIfErrorWMsg(err, out, t)
   996  	catMD5Sum := GetMD5Sum([]byte(out))
   997  
   998  	if catMD5Sum != file.md5Sum {
   999  		fatalMsgOnly(fmt.Sprintf(
  1000  			"expected md5sum %s but we got %s",
  1001  			file.md5Sum,
  1002  			catMD5Sum,
  1003  		), t)
  1004  	}
  1005  
  1006  	if int64(len(out)) != file.diskStat.Size() {
  1007  		fatalMsgOnly(fmt.Sprintf(
  1008  			"file size is %d but we got %d",
  1009  			file.diskStat.Size(),
  1010  			len(out),
  1011  		), t)
  1012  	}
  1013  
  1014  	fatalIfErrorWMsg(
  1015  		err,
  1016  		"cat length: "+strconv.Itoa(len(out))+" -- file length:"+strconv.Itoa(int(file.diskStat.Size())),
  1017  		t,
  1018  	)
  1019  }
  1020  
  1021  func CopyObjectWithSSES3ToNewBucket(t *testing.T) {
  1022  	file := createFile(newTestFile{
  1023  		addToGlobalFileMap: false,
  1024  		tag:                "encbucketcopy-s3",
  1025  		sizeInMBS:          1,
  1026  	})
  1027  
  1028  	out, err := RunMC(
  1029  		"cp",
  1030  		"--enc-s3="+sseTestBucket,
  1031  		file.diskFile.Name(),
  1032  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1033  	)
  1034  	fatalIfErrorWMsg(err, out, t)
  1035  
  1036  	TargetSSEBucket := CreateBucket(t)
  1037  
  1038  	out, err = RunMC(
  1039  		"cp",
  1040  		"--enc-s3="+TargetSSEBucket,
  1041  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1042  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1043  	)
  1044  	fatalIfErrorWMsg(err, out, t)
  1045  
  1046  	out, err = RunMC(
  1047  		"cp",
  1048  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1049  		file.diskFile.Name()+".download",
  1050  	)
  1051  	fatalIfErrorWMsg(err, out, t)
  1052  
  1053  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1054  	fatalIfError(err, t)
  1055  	if md5s != file.md5Sum {
  1056  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1057  	}
  1058  }
  1059  
  1060  func MirrorTempDirectoryUsingSSES3(t *testing.T) {
  1061  	MirrorBucket := CreateBucket(t)
  1062  
  1063  	subDir := "encmirror-s3"
  1064  
  1065  	f1 := createFile(newTestFile{
  1066  		addToGlobalFileMap: false,
  1067  		subDir:             subDir,
  1068  		tag:                "encmirror1-s3",
  1069  		sizeInMBS:          1,
  1070  	})
  1071  
  1072  	f2 := createFile(newTestFile{
  1073  		addToGlobalFileMap: false,
  1074  		subDir:             subDir,
  1075  		tag:                "encmirror2-s3",
  1076  		sizeInMBS:          2,
  1077  	})
  1078  
  1079  	f3 := createFile(newTestFile{
  1080  		addToGlobalFileMap: false,
  1081  		subDir:             subDir,
  1082  		tag:                "encmirror3-s3",
  1083  		sizeInMBS:          4,
  1084  	})
  1085  
  1086  	files := append([]*testFile{}, f1, f2, f3)
  1087  
  1088  	out, err := RunMC(
  1089  		"mirror",
  1090  		"--enc-s3="+MirrorBucket,
  1091  		tempDir+string(os.PathSeparator)+subDir,
  1092  		MirrorBucket,
  1093  	)
  1094  	fatalIfErrorWMsg(err, out, t)
  1095  
  1096  	out, err = RunMC("ls", "-r", MirrorBucket)
  1097  	fatalIfError(err, t)
  1098  
  1099  	fileList, err := parseLSJSONOutput(out)
  1100  	fatalIfError(err, t)
  1101  
  1102  	for i, f := range files {
  1103  		fileFound := false
  1104  
  1105  		for _, o := range fileList {
  1106  			if o.Key == f.fileNameWithoutPath {
  1107  				files[i].MinioLS = o
  1108  				fileFound = true
  1109  			}
  1110  		}
  1111  
  1112  		if !fileFound {
  1113  			fatalMsgOnly(fmt.Sprintf(
  1114  				"File was not uploaded: %s",
  1115  				f.fileNameWithPrefix,
  1116  			), t)
  1117  		}
  1118  
  1119  		out, err := RunMC("stat", MirrorBucket+"/"+files[i].MinioLS.Key)
  1120  		fatalIfError(err, t)
  1121  		stat, err := parseStatSingleObjectJSONOutput(out)
  1122  		fatalIfError(err, t)
  1123  		files[i].MinioStat = stat
  1124  
  1125  		foundKmsTag := false
  1126  		for ii := range stat.Metadata {
  1127  			if ii == amzObjectSSE {
  1128  				foundKmsTag = true
  1129  				break
  1130  			}
  1131  		}
  1132  
  1133  		if !foundKmsTag {
  1134  			fmt.Println(stat)
  1135  			fatalMsgOnly(amzObjectSSEKMSKeyID+" not found for object "+files[i].MinioLS.Key, t)
  1136  		}
  1137  
  1138  	}
  1139  }
  1140  
  1141  func PutObjectWithSSES3PartialPrefixMatch(t *testing.T) {
  1142  	file := createFile(newTestFile{
  1143  		addToGlobalFileMap: false,
  1144  		tag:                "encput-s3-prefix-test",
  1145  		sizeInMBS:          1,
  1146  	})
  1147  
  1148  	out, err := RunMC(
  1149  		"cp",
  1150  		"--enc-s3="+sseTestBucket+"/"+file.fileNameWithoutPath,
  1151  		file.diskFile.Name(),
  1152  		sseTestBucket,
  1153  	)
  1154  	fatalIfErrorWMsg(err, out, t)
  1155  }
  1156  
  1157  func PutObjectWithSSES3(t *testing.T) {
  1158  	file := createFile(newTestFile{
  1159  		addToGlobalFileMap: false,
  1160  		tag:                "encput-s3",
  1161  		sizeInMBS:          1,
  1162  	})
  1163  
  1164  	out, err := RunMC(
  1165  		"cp",
  1166  		"--enc-s3="+sseTestBucket,
  1167  		file.diskFile.Name(),
  1168  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1169  	)
  1170  	fatalIfErrorWMsg(err, out, t)
  1171  }
  1172  
  1173  func PutObjectWithSSES3Multipart(t *testing.T) {
  1174  	file := createFile(newTestFile{
  1175  		addToGlobalFileMap: false,
  1176  		tag:                "encmultiput-s3",
  1177  		sizeInMBS:          68,
  1178  	})
  1179  
  1180  	out, err := RunMC(
  1181  		"cp",
  1182  		"--enc-s3="+sseTestBucket,
  1183  		file.diskFile.Name(),
  1184  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1185  	)
  1186  	fatalIfErrorWMsg(err, out, t)
  1187  }
  1188  
  1189  func GetObjectWithSSEKMS(t *testing.T) {
  1190  	file := createFile(newTestFile{
  1191  		addToGlobalFileMap: false,
  1192  		tag:                "encget-kms",
  1193  		sizeInMBS:          1,
  1194  	})
  1195  
  1196  	out, err := RunMC(
  1197  		"cp",
  1198  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1199  		file.diskFile.Name(),
  1200  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1201  	)
  1202  	fatalIfErrorWMsg(err, out, t)
  1203  
  1204  	out, err = RunMC(
  1205  		"cp",
  1206  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1207  		file.diskFile.Name()+".download",
  1208  	)
  1209  	fatalIfErrorWMsg(err, out, t)
  1210  
  1211  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1212  	fatalIfError(err, t)
  1213  	if md5s != file.md5Sum {
  1214  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1215  	}
  1216  }
  1217  
  1218  func PutObjectWithSSECMultipart(t *testing.T) {
  1219  	file := createFile(newTestFile{
  1220  		addToGlobalFileMap: false,
  1221  		tag:                "encmultiput",
  1222  		sizeInMBS:          68,
  1223  	})
  1224  
  1225  	out, err := RunMC(
  1226  		"cp",
  1227  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1228  		file.diskFile.Name(),
  1229  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1230  	)
  1231  	fatalIfErrorWMsg(err, out, t)
  1232  }
  1233  
  1234  func CatObjectWithSSEKMS(t *testing.T) {
  1235  	file := createFile(newTestFile{
  1236  		addToGlobalFileMap: false,
  1237  		tag:                "enccat-kms",
  1238  		sizeInMBS:          1,
  1239  	})
  1240  
  1241  	out, err := RunMC(
  1242  		"cp",
  1243  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1244  		file.diskFile.Name(),
  1245  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1246  	)
  1247  	fatalIfErrorWMsg(err, out, t)
  1248  
  1249  	out, err = RunMC(
  1250  		"cat",
  1251  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1252  	)
  1253  	fatalIfErrorWMsg(err, out, t)
  1254  	catMD5Sum := GetMD5Sum([]byte(out))
  1255  
  1256  	if catMD5Sum != file.md5Sum {
  1257  		fatalMsgOnly(fmt.Sprintf(
  1258  			"expected md5sum %s but we got %s",
  1259  			file.md5Sum,
  1260  			catMD5Sum,
  1261  		), t)
  1262  	}
  1263  
  1264  	if int64(len(out)) != file.diskStat.Size() {
  1265  		fatalMsgOnly(fmt.Sprintf(
  1266  			"file size is %d but we got %d",
  1267  			file.diskStat.Size(),
  1268  			len(out),
  1269  		), t)
  1270  	}
  1271  
  1272  	fatalIfErrorWMsg(
  1273  		err,
  1274  		"cat length: "+strconv.Itoa(len(out))+" -- file length:"+strconv.Itoa(int(file.diskStat.Size())),
  1275  		t,
  1276  	)
  1277  }
  1278  
  1279  func PutObjectWithSSECPartialPrefixMatch(t *testing.T) {
  1280  	file := createFile(newTestFile{
  1281  		addToGlobalFileMap: false,
  1282  		tag:                "encput-prefix-test",
  1283  		sizeInMBS:          1,
  1284  	})
  1285  
  1286  	out, err := RunMC(
  1287  		"cp",
  1288  		"--enc-c="+sseTestBucket+"/"+file.fileNameWithoutPath+"="+sseBaseEncodedKey,
  1289  		file.diskFile.Name(),
  1290  		sseTestBucket,
  1291  	)
  1292  	fatalIfErrorWMsg(err, out, t)
  1293  }
  1294  
  1295  func PutObjectWithSSEC(t *testing.T) {
  1296  	file := createFile(newTestFile{
  1297  		addToGlobalFileMap: false,
  1298  		tag:                "encput",
  1299  		sizeInMBS:          1,
  1300  	})
  1301  
  1302  	out, err := RunMC(
  1303  		"cp",
  1304  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1305  		file.diskFile.Name(),
  1306  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1307  	)
  1308  	fatalIfErrorWMsg(err, out, t)
  1309  }
  1310  
  1311  func PutObjectErrorWithSSECOverHTTP(t *testing.T) {
  1312  	file := createFile(newTestFile{
  1313  		addToGlobalFileMap: false,
  1314  		tag:                "encput-http",
  1315  		sizeInMBS:          1,
  1316  	})
  1317  
  1318  	out, err := RunMC(
  1319  		"cp",
  1320  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1321  		file.diskFile.Name(),
  1322  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1323  	)
  1324  	fatalIfNoErrorWMsg(err, out, t)
  1325  }
  1326  
  1327  func PutObjectWithSSECInvalidKeys(t *testing.T) {
  1328  	file := createFile(newTestFile{
  1329  		addToGlobalFileMap: false,
  1330  		tag:                "encerror-dep",
  1331  		sizeInMBS:          1,
  1332  	})
  1333  
  1334  	out, err := RunMC(
  1335  		"cp",
  1336  		"--enc-c="+sseTestBucket+"="+invalidSSEBaseEncodedKey,
  1337  		file.diskFile.Name(),
  1338  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1339  	)
  1340  	fatalIfNoErrorWMsg(err, out, t)
  1341  }
  1342  
  1343  func GetObjectWithSSEC(t *testing.T) {
  1344  	file := createFile(newTestFile{
  1345  		addToGlobalFileMap: false,
  1346  		tag:                "encget",
  1347  		sizeInMBS:          1,
  1348  	})
  1349  
  1350  	out, err := RunMC(
  1351  		"cp",
  1352  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1353  		file.diskFile.Name(),
  1354  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1355  	)
  1356  	fatalIfErrorWMsg(err, out, t)
  1357  
  1358  	out, err = RunMC(
  1359  		"cp",
  1360  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1361  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1362  		file.diskFile.Name()+".download",
  1363  	)
  1364  	fatalIfErrorWMsg(err, out, t)
  1365  
  1366  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1367  	fatalIfError(err, t)
  1368  	if md5s != file.md5Sum {
  1369  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1370  	}
  1371  }
  1372  
  1373  func GetObjectWithSSECWithoutKey(t *testing.T) {
  1374  	file := createFile(newTestFile{
  1375  		addToGlobalFileMap: false,
  1376  		tag:                "encerror",
  1377  		sizeInMBS:          1,
  1378  	})
  1379  
  1380  	out, err := RunMC(
  1381  		"cp",
  1382  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1383  		file.diskFile.Name(),
  1384  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1385  	)
  1386  	fatalIfErrorWMsg(err, out, t)
  1387  
  1388  	out, err = RunMC(
  1389  		"cp",
  1390  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1391  		file.diskFile.Name()+"-get",
  1392  	)
  1393  	fatalIfNoErrorWMsg(err, out, t)
  1394  }
  1395  
  1396  func CatObjectWithSSEC(t *testing.T) {
  1397  	file := createFile(newTestFile{
  1398  		addToGlobalFileMap: false,
  1399  		tag:                "enccat",
  1400  		sizeInMBS:          1,
  1401  	})
  1402  
  1403  	out, err := RunMC(
  1404  		"cp",
  1405  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1406  		file.diskFile.Name(),
  1407  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1408  	)
  1409  	fatalIfErrorWMsg(err, out, t)
  1410  
  1411  	out, err = RunMC(
  1412  		"cat",
  1413  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1414  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1415  	)
  1416  	fatalIfErrorWMsg(err, out, t)
  1417  	catMD5Sum := GetMD5Sum([]byte(out))
  1418  
  1419  	if catMD5Sum != file.md5Sum {
  1420  		fatalMsgOnly(fmt.Sprintf(
  1421  			"expected md5sum %s but we got %s",
  1422  			file.md5Sum,
  1423  			catMD5Sum,
  1424  		), t)
  1425  	}
  1426  
  1427  	if int64(len(out)) != file.diskStat.Size() {
  1428  		fatalMsgOnly(fmt.Sprintf(
  1429  			"file size is %d but we got %d",
  1430  			file.diskStat.Size(),
  1431  			len(out),
  1432  		), t)
  1433  	}
  1434  
  1435  	fatalIfErrorWMsg(
  1436  		err,
  1437  		"cat length: "+strconv.Itoa(len(out))+" -- file length:"+strconv.Itoa(int(file.diskStat.Size())),
  1438  		t,
  1439  	)
  1440  }
  1441  
  1442  func CopyObjectWithSSEKMSWithOverLappingKeys(t *testing.T) {
  1443  	file := createFile(newTestFile{
  1444  		addToGlobalFileMap: false,
  1445  		tag:                "encbucketcopy-kms",
  1446  		sizeInMBS:          1,
  1447  	})
  1448  
  1449  	out, err := RunMC(
  1450  		"cp",
  1451  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1452  		file.diskFile.Name(),
  1453  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1454  	)
  1455  	fatalIfErrorWMsg(err, out, t)
  1456  
  1457  	TargetSSEBucket := CreateBucket(t)
  1458  
  1459  	out, err = RunMC(
  1460  		"cp",
  1461  		"--enc-kms="+TargetSSEBucket+"="+sseKMSKeyName,
  1462  		"--enc-kms="+TargetSSEBucket+"="+sseKMSKeyName,
  1463  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1464  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1465  	)
  1466  	fatalIfNoErrorWMsg(err, out, t)
  1467  }
  1468  
  1469  func CopyObjectWithSSEKMSToNewBucket(t *testing.T) {
  1470  	file := createFile(newTestFile{
  1471  		addToGlobalFileMap: false,
  1472  		tag:                "encbucketcopy-kms",
  1473  		sizeInMBS:          1,
  1474  	})
  1475  
  1476  	out, err := RunMC(
  1477  		"cp",
  1478  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1479  		file.diskFile.Name(),
  1480  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1481  	)
  1482  	fatalIfErrorWMsg(err, out, t)
  1483  
  1484  	TargetSSEBucket := CreateBucket(t)
  1485  
  1486  	out, err = RunMC(
  1487  		"cp",
  1488  		"--enc-kms="+TargetSSEBucket+"="+sseKMSKeyName,
  1489  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1490  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1491  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1492  	)
  1493  	fatalIfErrorWMsg(err, out, t)
  1494  
  1495  	out, err = RunMC(
  1496  		"cp",
  1497  		"--enc-kms="+TargetSSEBucket+"="+sseKMSKeyName,
  1498  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1499  		file.diskFile.Name()+".download",
  1500  	)
  1501  	fatalIfErrorWMsg(err, out, t)
  1502  
  1503  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1504  	fatalIfError(err, t)
  1505  	if md5s != file.md5Sum {
  1506  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1507  	}
  1508  }
  1509  
  1510  func CopyObjectWithSSEKMSToNewBucketWithSSEC(t *testing.T) {
  1511  	file := createFile(newTestFile{
  1512  		addToGlobalFileMap: false,
  1513  		tag:                "encbucketcopy-kms-c",
  1514  		sizeInMBS:          1,
  1515  	})
  1516  
  1517  	out, err := RunMC(
  1518  		"cp",
  1519  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1520  		file.diskFile.Name(),
  1521  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1522  	)
  1523  	fatalIfErrorWMsg(err, out, t)
  1524  
  1525  	TargetSSEBucket := CreateBucket(t)
  1526  
  1527  	out, err = RunMC(
  1528  		"cp",
  1529  		"--enc-c="+TargetSSEBucket+"="+sseBaseEncodedKey,
  1530  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1531  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1532  	)
  1533  	fatalIfErrorWMsg(err, out, t)
  1534  
  1535  	out, err = RunMC(
  1536  		"cp",
  1537  		"--enc-c="+TargetSSEBucket+"="+sseBaseEncodedKey,
  1538  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1539  		file.diskFile.Name()+".download",
  1540  	)
  1541  	fatalIfErrorWMsg(err, out, t)
  1542  
  1543  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1544  	fatalIfError(err, t)
  1545  	if md5s != file.md5Sum {
  1546  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1547  	}
  1548  }
  1549  
  1550  func MirrorTempDirectoryUsingSSEKMS(t *testing.T) {
  1551  	MirrorBucket := CreateBucket(t)
  1552  
  1553  	subDir := "encmirror-kms"
  1554  
  1555  	f1 := createFile(newTestFile{
  1556  		addToGlobalFileMap: false,
  1557  		subDir:             subDir,
  1558  		tag:                "encmirror1-kms",
  1559  		sizeInMBS:          1,
  1560  	})
  1561  
  1562  	f2 := createFile(newTestFile{
  1563  		addToGlobalFileMap: false,
  1564  		subDir:             subDir,
  1565  		tag:                "encmirror2-kms",
  1566  		sizeInMBS:          2,
  1567  	})
  1568  
  1569  	f3 := createFile(newTestFile{
  1570  		addToGlobalFileMap: false,
  1571  		subDir:             subDir,
  1572  		tag:                "encmirror3-kms",
  1573  		sizeInMBS:          4,
  1574  	})
  1575  
  1576  	files := append([]*testFile{}, f1, f2, f3)
  1577  
  1578  	out, err := RunMC(
  1579  		"mirror",
  1580  		"--enc-kms="+MirrorBucket+"="+sseKMSKeyName,
  1581  		tempDir+string(os.PathSeparator)+subDir,
  1582  		MirrorBucket,
  1583  	)
  1584  	fatalIfErrorWMsg(err, out, t)
  1585  
  1586  	out, err = RunMC("ls", "-r", MirrorBucket)
  1587  	fatalIfError(err, t)
  1588  
  1589  	fileList, err := parseLSJSONOutput(out)
  1590  	fatalIfError(err, t)
  1591  
  1592  	for i, f := range files {
  1593  		fileFound := false
  1594  
  1595  		for _, o := range fileList {
  1596  			if o.Key == f.fileNameWithoutPath {
  1597  				files[i].MinioLS = o
  1598  				fileFound = true
  1599  			}
  1600  		}
  1601  
  1602  		if !fileFound {
  1603  			fatalMsgOnly(fmt.Sprintf(
  1604  				"File was not uploaded: %s",
  1605  				f.fileNameWithPrefix,
  1606  			), t)
  1607  		}
  1608  
  1609  		out, err := RunMC("stat", MirrorBucket+"/"+files[i].MinioLS.Key)
  1610  		fatalIfError(err, t)
  1611  		stat, err := parseStatSingleObjectJSONOutput(out)
  1612  		fatalIfError(err, t)
  1613  		files[i].MinioStat = stat
  1614  
  1615  		foundKmsTag := false
  1616  		for ii, v := range stat.Metadata {
  1617  			if ii == amzObjectSSEKMSKeyID {
  1618  				foundKmsTag = true
  1619  				if !strings.HasSuffix(v, sseKMSKeyName) {
  1620  					fatalMsgOnly("invalid KMS key for object "+files[i].MinioLS.Key, t)
  1621  					break
  1622  				}
  1623  			}
  1624  		}
  1625  
  1626  		if !foundKmsTag {
  1627  			fatalMsgOnly(amzObjectSSEKMSKeyID+" not found for object "+files[i].MinioLS.Key, t)
  1628  		}
  1629  
  1630  	}
  1631  }
  1632  
  1633  func RemoveObjectWithSSEKMS(t *testing.T) {
  1634  	file := createFile(newTestFile{
  1635  		addToGlobalFileMap: false,
  1636  		tag:                "encrm-kms",
  1637  		sizeInMBS:          1,
  1638  	})
  1639  
  1640  	out, err := RunMC(
  1641  		"cp",
  1642  		"--enc-kms="+sseTestBucket+"="+sseKMSKeyName,
  1643  		file.diskFile.Name(),
  1644  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1645  	)
  1646  	fatalIfErrorWMsg(err, out, t)
  1647  
  1648  	out, err = RunMC(
  1649  		"rm",
  1650  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1651  	)
  1652  	fatalIfErrorWMsg(err, out, t)
  1653  
  1654  	out, err = RunMC(
  1655  		"stat",
  1656  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1657  	)
  1658  	fatalIfNoErrorWMsg(err, out, t)
  1659  }
  1660  
  1661  func CatObjectWithSSECWithoutKey(t *testing.T) {
  1662  	file := createFile(newTestFile{
  1663  		addToGlobalFileMap: false,
  1664  		tag:                "encerror",
  1665  		sizeInMBS:          1,
  1666  	})
  1667  
  1668  	out, err := RunMC(
  1669  		"cp",
  1670  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1671  		file.diskFile.Name(),
  1672  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1673  	)
  1674  	fatalIfErrorWMsg(err, out, t)
  1675  
  1676  	out, err = RunMC(
  1677  		"cat",
  1678  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1679  		file.diskFile.Name()+"-cat",
  1680  	)
  1681  	fatalIfNoErrorWMsg(err, out, t)
  1682  }
  1683  
  1684  func RemoveObjectWithSSEC(t *testing.T) {
  1685  	file := createFile(newTestFile{
  1686  		addToGlobalFileMap: false,
  1687  		tag:                "encrm",
  1688  		sizeInMBS:          1,
  1689  	})
  1690  
  1691  	out, err := RunMC(
  1692  		"cp",
  1693  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1694  		file.diskFile.Name(),
  1695  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1696  	)
  1697  	fatalIfErrorWMsg(err, out, t)
  1698  
  1699  	out, err = RunMC(
  1700  		"rm",
  1701  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1702  	)
  1703  	fatalIfErrorWMsg(err, out, t)
  1704  
  1705  	out, err = RunMC(
  1706  		"stat",
  1707  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1708  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1709  	)
  1710  	fatalIfNoErrorWMsg(err, out, t)
  1711  }
  1712  
  1713  func MirrorTempDirectoryUsingSSEC(t *testing.T) {
  1714  	MirrorBucket := CreateBucket(t)
  1715  
  1716  	subDir := "encmirror"
  1717  
  1718  	f1 := createFile(newTestFile{
  1719  		addToGlobalFileMap: false,
  1720  		subDir:             subDir,
  1721  		tag:                "encmirror1",
  1722  		sizeInMBS:          1,
  1723  	})
  1724  
  1725  	f2 := createFile(newTestFile{
  1726  		addToGlobalFileMap: false,
  1727  		subDir:             subDir,
  1728  		tag:                "encmirror2",
  1729  		sizeInMBS:          2,
  1730  	})
  1731  
  1732  	f3 := createFile(newTestFile{
  1733  		addToGlobalFileMap: false,
  1734  		subDir:             subDir,
  1735  		tag:                "encmirror3",
  1736  		sizeInMBS:          4,
  1737  	})
  1738  
  1739  	files := append([]*testFile{}, f1, f2, f3)
  1740  
  1741  	out, err := RunMC(
  1742  		"mirror",
  1743  		"--enc-c="+MirrorBucket+"="+sseBaseEncodedKey,
  1744  		tempDir+string(os.PathSeparator)+subDir,
  1745  		MirrorBucket,
  1746  	)
  1747  	fatalIfErrorWMsg(err, out, t)
  1748  
  1749  	out, err = RunMC("ls", "-r", MirrorBucket)
  1750  	fatalIfError(err, t)
  1751  
  1752  	fileList, err := parseLSJSONOutput(out)
  1753  	fatalIfError(err, t)
  1754  
  1755  	for i, f := range files {
  1756  		fileFound := false
  1757  
  1758  		for _, o := range fileList {
  1759  			if o.Key == f.fileNameWithoutPath {
  1760  				files[i].MinioLS = o
  1761  				fileFound = true
  1762  			}
  1763  		}
  1764  
  1765  		if !fileFound {
  1766  			fatalMsgOnly(fmt.Sprintf(
  1767  				"File was not uploaded: %s",
  1768  				f.fileNameWithPrefix,
  1769  			), t)
  1770  		}
  1771  
  1772  		out, err := RunMC(
  1773  			"stat",
  1774  			"--enc-c="+MirrorBucket+"="+sseBaseEncodedKey,
  1775  			MirrorBucket+"/"+files[i].MinioLS.Key,
  1776  		)
  1777  		fatalIfError(err, t)
  1778  		_, err = parseStatSingleObjectJSONOutput(out)
  1779  		fatalIfError(err, t)
  1780  
  1781  	}
  1782  }
  1783  
  1784  func CopyObjectWithSSECToNewBucketWithNewKey(t *testing.T) {
  1785  	file := createFile(newTestFile{
  1786  		addToGlobalFileMap: false,
  1787  		tag:                "encbucketcopy",
  1788  		sizeInMBS:          1,
  1789  	})
  1790  
  1791  	out, err := RunMC(
  1792  		"cp",
  1793  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1794  		file.diskFile.Name(),
  1795  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1796  	)
  1797  	fatalIfErrorWMsg(err, out, t)
  1798  
  1799  	TargetSSEBucket := CreateBucket(t)
  1800  
  1801  	out, err = RunMC(
  1802  		"cp",
  1803  		"--enc-c="+TargetSSEBucket+"="+sseBaseEncodedKey2,
  1804  		"--enc-c="+sseTestBucket+"="+sseBaseEncodedKey,
  1805  		sseTestBucket+"/"+file.fileNameWithoutPath,
  1806  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1807  	)
  1808  	fatalIfErrorWMsg(err, out, t)
  1809  
  1810  	out, err = RunMC(
  1811  		"cp",
  1812  		"--enc-c="+TargetSSEBucket+"="+sseBaseEncodedKey2,
  1813  		TargetSSEBucket+"/"+file.fileNameWithoutPath,
  1814  		file.diskFile.Name()+".download",
  1815  	)
  1816  	fatalIfErrorWMsg(err, out, t)
  1817  
  1818  	md5s, err := openFileAndGetMd5Sum(file.diskFile.Name() + ".download")
  1819  	fatalIfError(err, t)
  1820  	if md5s != file.md5Sum {
  1821  		fatalMsgOnly(fmt.Sprintf("expecting md5sum (%s) but got sum (%s)", file.md5Sum, md5s), t)
  1822  	}
  1823  }
  1824  
  1825  func uploadAllFiles(t *testing.T) {
  1826  	for _, v := range fileMap {
  1827  		parameters := make([]string, 0)
  1828  		parameters = append(parameters, "cp")
  1829  
  1830  		if v.storageClass != "" {
  1831  			parameters = append(parameters, "--storage-class", v.storageClass)
  1832  		}
  1833  
  1834  		if len(v.metaData) > 0 {
  1835  			parameters = append(parameters, "--attr")
  1836  			meta := ""
  1837  			for i, v := range v.metaData {
  1838  				meta += i + "=" + v + ";"
  1839  			}
  1840  			meta = strings.TrimSuffix(meta, ";")
  1841  			parameters = append(parameters, meta)
  1842  		}
  1843  		if len(v.tags) > 0 {
  1844  			parameters = append(parameters, "--tags")
  1845  			tags := ""
  1846  			for i, v := range v.tags {
  1847  				tags += i + "=" + v + ";"
  1848  			}
  1849  			tags = strings.TrimSuffix(tags, ";")
  1850  			parameters = append(parameters, tags)
  1851  		}
  1852  
  1853  		parameters = append(parameters, v.diskFile.Name())
  1854  
  1855  		if v.prefix != "" {
  1856  			parameters = append(
  1857  				parameters,
  1858  				mainTestBucket+"/"+v.fileNameWithPrefix,
  1859  			)
  1860  		} else {
  1861  			parameters = append(
  1862  				parameters,
  1863  				mainTestBucket+"/"+v.fileNameWithoutPath,
  1864  			)
  1865  		}
  1866  
  1867  		_, err := RunMC(parameters...)
  1868  		if err != nil {
  1869  			t.Fatal(err)
  1870  		}
  1871  	}
  1872  }
  1873  
  1874  func OD(t *testing.T) {
  1875  	LocalBucketPath := CreateBucket(t)
  1876  
  1877  	file := fileMap["65M"]
  1878  	out, err := RunMC(
  1879  		"od",
  1880  		"if="+file.diskFile.Name(),
  1881  		"of="+LocalBucketPath+"/od/"+file.fileNameWithoutPath,
  1882  		"parts=10",
  1883  	)
  1884  
  1885  	fatalIfError(err, t)
  1886  	odMsg, err := parseSingleODMessageJSONOutput(out)
  1887  	fatalIfError(err, t)
  1888  
  1889  	if odMsg.TotalSize != file.diskStat.Size() {
  1890  		t.Fatalf(
  1891  			"Expected (%d) bytes to be uploaded but only uploaded (%d) bytes",
  1892  			odMsg.TotalSize,
  1893  			file.diskStat.Size(),
  1894  		)
  1895  	}
  1896  
  1897  	if odMsg.Parts != 10 {
  1898  		t.Fatalf(
  1899  			"Expected upload parts to be (10) but they were (%d)",
  1900  			odMsg.Parts,
  1901  		)
  1902  	}
  1903  
  1904  	if odMsg.Type != "FStoS3" {
  1905  		t.Fatalf(
  1906  			"Expected type to be (FStoS3) but got (%s)",
  1907  			odMsg.Type,
  1908  		)
  1909  	}
  1910  
  1911  	if odMsg.PartSize != uint64(file.diskStat.Size())/10 {
  1912  		t.Fatalf(
  1913  			"Expected part size to be (%d) but got (%d)",
  1914  			file.diskStat.Size()/10,
  1915  			odMsg.PartSize,
  1916  		)
  1917  	}
  1918  
  1919  	out, err = RunMC(
  1920  		"od",
  1921  		"of="+file.diskFile.Name(),
  1922  		"if="+LocalBucketPath+"/od/"+file.fileNameWithoutPath,
  1923  		"parts=10",
  1924  	)
  1925  
  1926  	fatalIfError(err, t)
  1927  	fmt.Println(out)
  1928  	odMsg, err = parseSingleODMessageJSONOutput(out)
  1929  	fatalIfError(err, t)
  1930  
  1931  	if odMsg.TotalSize != file.diskStat.Size() {
  1932  		t.Fatalf(
  1933  			"Expected (%d) bytes to be uploaded but only uploaded (%d) bytes",
  1934  			odMsg.TotalSize,
  1935  			file.diskStat.Size(),
  1936  		)
  1937  	}
  1938  
  1939  	if odMsg.Parts != 10 {
  1940  		t.Fatalf(
  1941  			"Expected upload parts to be (10) but they were (%d)",
  1942  			odMsg.Parts,
  1943  		)
  1944  	}
  1945  
  1946  	if odMsg.Type != "S3toFS" {
  1947  		t.Fatalf(
  1948  			"Expected type to be (FStoS3) but got (%s)",
  1949  			odMsg.Type,
  1950  		)
  1951  	}
  1952  
  1953  	if odMsg.PartSize != uint64(file.diskStat.Size())/10 {
  1954  		t.Fatalf(
  1955  			"Expected part size to be (%d) but got (%d)",
  1956  			file.diskStat.Size()/10,
  1957  			odMsg.PartSize,
  1958  		)
  1959  	}
  1960  }
  1961  
  1962  func MvFromDiskToMinio(t *testing.T) {
  1963  	LocalBucketPath := CreateBucket(t)
  1964  
  1965  	file := createFile(newTestFile{
  1966  		addToGlobalFileMap: false,
  1967  		tag:                "10Move",
  1968  		prefix:             "",
  1969  		extension:          ".txt",
  1970  		storageClass:       "",
  1971  		sizeInMBS:          1,
  1972  		metaData:           map[string]string{"name": "10Move"},
  1973  		tags:               map[string]string{"tag1": "10Move-tag"},
  1974  	})
  1975  
  1976  	out, err := RunMC(
  1977  		"mv",
  1978  		file.diskFile.Name(),
  1979  		LocalBucketPath+"/"+file.fileNameWithoutPath,
  1980  	)
  1981  
  1982  	fatalIfError(err, t)
  1983  	splitReturn := bytes.Split([]byte(out), []byte{10})
  1984  
  1985  	mvMSG, err := parseSingleCPMessageJSONOutput(string(splitReturn[0]))
  1986  	fatalIfError(err, t)
  1987  
  1988  	if mvMSG.TotalCount != 1 {
  1989  		t.Fatalf("Expected count to be 1 but got (%d)", mvMSG.TotalCount)
  1990  	}
  1991  
  1992  	if mvMSG.Size != file.diskStat.Size() {
  1993  		t.Fatalf(
  1994  			"Expected size to be (%d) but got (%d)",
  1995  			file.diskStat.Size(),
  1996  			mvMSG.Size,
  1997  		)
  1998  	}
  1999  
  2000  	if mvMSG.Status != "success" {
  2001  		t.Fatalf(
  2002  			"Expected status to be (success) but got (%s)",
  2003  			mvMSG.Status,
  2004  		)
  2005  	}
  2006  
  2007  	statMSG, err := parseSingleAccountStatJSONOutput(string(splitReturn[1]))
  2008  	fatalIfError(err, t)
  2009  
  2010  	if statMSG.Transferred != file.diskStat.Size() {
  2011  		t.Fatalf(
  2012  			"Expected transfeered to be (%d) but got (%d)",
  2013  			file.diskStat.Size(),
  2014  			statMSG.Transferred,
  2015  		)
  2016  	}
  2017  
  2018  	if statMSG.Total != file.diskStat.Size() {
  2019  		t.Fatalf(
  2020  			"Expected total to be (%d) but got (%d)",
  2021  			file.diskStat.Size(),
  2022  			statMSG.Total,
  2023  		)
  2024  	}
  2025  
  2026  	if statMSG.Status != "success" {
  2027  		t.Fatalf(
  2028  			"Expected status to be (success) but got (%s)",
  2029  			statMSG.Status,
  2030  		)
  2031  	}
  2032  }
  2033  
  2034  func DUBucket(t *testing.T) {
  2035  	var totalFileSize int64
  2036  	for _, v := range fileMap {
  2037  		totalFileSize += v.MinioStat.Size
  2038  	}
  2039  
  2040  	out, err := RunMC("du", mainTestBucket)
  2041  	fatalIfError(err, t)
  2042  
  2043  	duList, err := parseDUJSONOutput(out)
  2044  	fatalIfError(err, t)
  2045  	if len(duList) != 1 {
  2046  		fatalMsgOnly("Expected 1 result to be returned", t)
  2047  	}
  2048  	if duList[0].Size != totalFileSize {
  2049  		fatalMsgOnly(
  2050  			fmt.Sprintf("total size to be %d but got %d", totalFileSize, duList[0].Size),
  2051  			t,
  2052  		)
  2053  	}
  2054  }
  2055  
  2056  func LSObjects(t *testing.T) {
  2057  	out, err := RunMC("ls", "-r", mainTestBucket)
  2058  	fatalIfError(err, t)
  2059  
  2060  	fileList, err := parseLSJSONOutput(out)
  2061  	fatalIfError(err, t)
  2062  
  2063  	for i, f := range fileMap {
  2064  		fileFound := false
  2065  
  2066  		for _, o := range fileList {
  2067  			if o.Key == f.fileNameWithPrefix {
  2068  				fileMap[i].MinioLS = o
  2069  				fileFound = true
  2070  			}
  2071  		}
  2072  
  2073  		if !fileFound {
  2074  			t.Fatalf("File was not uploaded: %s", f.fileNameWithPrefix)
  2075  		}
  2076  	}
  2077  }
  2078  
  2079  func StatObjects(t *testing.T) {
  2080  	for i, v := range fileMap {
  2081  
  2082  		out, err := RunMC(
  2083  			"stat",
  2084  			mainTestBucket+"/"+v.fileNameWithPrefix,
  2085  		)
  2086  		fatalIfError(err, t)
  2087  
  2088  		fileMap[i].MinioStat, err = parseStatSingleObjectJSONOutput(out)
  2089  		fatalIfError(err, t)
  2090  
  2091  		if fileMap[i].MinioStat.Key == "" {
  2092  			t.Fatalf("Unable to stat Minio object (%s)", v.fileNameWithPrefix)
  2093  		}
  2094  
  2095  	}
  2096  }
  2097  
  2098  func ValidateFileMetaData(t *testing.T) {
  2099  	for _, f := range fileMap {
  2100  		validateFileLSInfo(t, f)
  2101  		validateObjectMetaData(t, f)
  2102  		// validateContentType(t, f)
  2103  	}
  2104  }
  2105  
  2106  func FindObjects(t *testing.T) {
  2107  	out, err := RunMC("find", mainTestBucket)
  2108  	fatalIfError(err, t)
  2109  
  2110  	findList, err := parseFindJSONOutput(out)
  2111  	fatalIfError(err, t)
  2112  
  2113  	for _, v := range fileMap {
  2114  
  2115  		found := false
  2116  		for _, vv := range findList {
  2117  			if strings.HasSuffix(vv.Key, v.MinioLS.Key) {
  2118  				found = true
  2119  			}
  2120  		}
  2121  
  2122  		if !found {
  2123  			t.Fatalf("File (%s) not found by 'find' command", v.MinioLS.Key)
  2124  		}
  2125  	}
  2126  }
  2127  
  2128  func FindObjectsUsingName(t *testing.T) {
  2129  	for _, v := range fileMap {
  2130  
  2131  		out, err := RunMC(
  2132  			"find",
  2133  			mainTestBucket,
  2134  			"--name",
  2135  			v.fileNameWithoutPath,
  2136  		)
  2137  
  2138  		fatalIfError(err, t)
  2139  		info, err := parseFindSingleObjectJSONOutput(out)
  2140  		fatalIfError(err, t)
  2141  		if !strings.HasSuffix(info.Key, v.MinioLS.Key) {
  2142  			t.Fatalf("Invalid key (%s) when searching for (%s)", info.Key, v.MinioLS.Key)
  2143  		}
  2144  
  2145  	}
  2146  }
  2147  
  2148  func FindObjectsUsingNameAndFilteringForTxtType(t *testing.T) {
  2149  	out, err := RunMC(
  2150  		"find",
  2151  		mainTestBucket,
  2152  		"--name",
  2153  		"*.txt",
  2154  	)
  2155  	fatalIfError(err, t)
  2156  
  2157  	findList, err := parseFindJSONOutput(out)
  2158  	fatalIfError(err, t)
  2159  
  2160  	for _, v := range fileMap {
  2161  		if v.extension != ".txt" {
  2162  			continue
  2163  		}
  2164  
  2165  		found := false
  2166  		for _, vv := range findList {
  2167  			if strings.HasSuffix(vv.Key, v.MinioLS.Key) {
  2168  				found = true
  2169  			}
  2170  		}
  2171  
  2172  		if !found {
  2173  			t.Fatalf("File (%s) not found by 'find' command", v.MinioLS.Key)
  2174  		}
  2175  	}
  2176  }
  2177  
  2178  func FindObjectsSmallerThan64Mebibytes(t *testing.T) {
  2179  	out, err := RunMC(
  2180  		"find",
  2181  		mainTestBucket,
  2182  		"--smaller",
  2183  		"64MB",
  2184  	)
  2185  	fatalIfError(err, t)
  2186  
  2187  	findList, err := parseFindJSONOutput(out)
  2188  	fatalIfError(err, t)
  2189  
  2190  	for _, v := range fileMap {
  2191  		if v.diskStat.Size() > GetMBSizeInBytes(64) {
  2192  			continue
  2193  		}
  2194  
  2195  		found := false
  2196  		for _, vv := range findList {
  2197  			if strings.HasSuffix(vv.Key, v.MinioLS.Key) {
  2198  				found = true
  2199  			}
  2200  		}
  2201  
  2202  		if !found {
  2203  			t.Fatalf("File (%s) not found by 'find' command", v.MinioLS.Key)
  2204  		}
  2205  	}
  2206  }
  2207  
  2208  func FindObjectsLargerThan64Mebibytes(t *testing.T) {
  2209  	out, err := RunMC(
  2210  		"find",
  2211  		mainTestBucket,
  2212  		"--larger",
  2213  		"64MB",
  2214  	)
  2215  	fatalIfError(err, t)
  2216  
  2217  	findList, err := parseFindJSONOutput(out)
  2218  	fatalIfError(err, t)
  2219  
  2220  	for _, v := range fileMap {
  2221  		if v.diskStat.Size() < GetMBSizeInBytes(64) {
  2222  			continue
  2223  		}
  2224  
  2225  		found := false
  2226  		for _, vv := range findList {
  2227  			if strings.HasSuffix(vv.Key, v.MinioLS.Key) {
  2228  				found = true
  2229  			}
  2230  		}
  2231  
  2232  		if !found {
  2233  			t.Fatalf("File (%s) not found by 'find' command", v.MinioLS.Key)
  2234  		}
  2235  	}
  2236  }
  2237  
  2238  func FindObjectsOlderThan1d(t *testing.T) {
  2239  	out, err := RunMC(
  2240  		"find",
  2241  		mainTestBucket,
  2242  		"--older-than",
  2243  		"1d",
  2244  	)
  2245  	fatalIfError(err, t)
  2246  
  2247  	findList, err := parseFindJSONOutput(out)
  2248  	fatalIfError(err, t)
  2249  
  2250  	if len(findList) > 0 {
  2251  		t.Fatalf("We should not have found any files which are older then 1 day")
  2252  	}
  2253  }
  2254  
  2255  func FindObjectsNewerThen1d(t *testing.T) {
  2256  	out, err := RunMC(
  2257  		"find",
  2258  		mainTestBucket,
  2259  		"--newer-than",
  2260  		"1d",
  2261  	)
  2262  	fatalIfError(err, t)
  2263  
  2264  	findList, err := parseFindJSONOutput(out)
  2265  	fatalIfError(err, t)
  2266  
  2267  	for _, v := range fileMap {
  2268  
  2269  		found := false
  2270  		for _, vv := range findList {
  2271  			if strings.HasSuffix(vv.Key, v.MinioLS.Key) {
  2272  				found = true
  2273  			}
  2274  		}
  2275  
  2276  		if !found {
  2277  			t.Fatalf("File (%s) not found by 'find' command", v.MinioLS.Key)
  2278  		}
  2279  	}
  2280  }
  2281  
  2282  func GetObjectsAndCompareMD5(t *testing.T) {
  2283  	for _, v := range fileMap {
  2284  
  2285  		// make sure old downloads are not in our way
  2286  		_ = os.Remove(tempDir + "/" + v.fileNameWithoutPath + ".downloaded")
  2287  
  2288  		_, err := RunMC(
  2289  			"cp",
  2290  			mainTestBucket+"/"+v.fileNameWithPrefix,
  2291  			tempDir+"/"+v.fileNameWithoutPath+".downloaded",
  2292  		)
  2293  		fatalIfError(err, t)
  2294  
  2295  		downloadedFile, err := os.Open(
  2296  			tempDir + "/" + v.fileNameWithoutPath + ".downloaded",
  2297  		)
  2298  		fatalIfError(err, t)
  2299  
  2300  		fileBytes, err := io.ReadAll(downloadedFile)
  2301  		fatalIfError(err, t)
  2302  		md5sum := GetMD5Sum(fileBytes)
  2303  
  2304  		if v.md5Sum != md5sum {
  2305  			t.Fatalf(
  2306  				"The downloaded file md5sum is wrong: original-md5(%s) downloaded-md5(%s)",
  2307  				v.md5Sum,
  2308  				md5sum,
  2309  			)
  2310  		}
  2311  	}
  2312  }
  2313  
  2314  func CreateBucketUsingInvalidSymbols(t *testing.T) {
  2315  	bucketNameMap := make(map[string]string)
  2316  	bucketNameMap["name-too-big"] = randomLargeString
  2317  	bucketNameMap["!"] = "symbol!"
  2318  	bucketNameMap["@"] = "symbol@"
  2319  	bucketNameMap["#"] = "symbol#"
  2320  	bucketNameMap["$"] = "symbol$"
  2321  	bucketNameMap["%"] = "symbol%"
  2322  	bucketNameMap["^"] = "symbol^"
  2323  	bucketNameMap["&"] = "symbol&"
  2324  	bucketNameMap["*"] = "symbol*"
  2325  	bucketNameMap["("] = "symbol("
  2326  	bucketNameMap[")"] = "symbol)"
  2327  	bucketNameMap["{"] = "symbol{"
  2328  	bucketNameMap["}"] = "symbol}"
  2329  	bucketNameMap["["] = "symbol["
  2330  	bucketNameMap["]"] = "symbol]"
  2331  
  2332  	for _, v := range bucketNameMap {
  2333  		_, err := RunMC("mb", defaultAlias+"/"+v)
  2334  		if err == nil {
  2335  			t.Fatalf("We should not have been able to create a bucket with the name: %s", v)
  2336  		}
  2337  	}
  2338  }
  2339  
  2340  func RemoveBucketThatDoesNotExist(t *testing.T) {
  2341  	randomID := uuid.NewString()
  2342  	out, _ := RunMC(
  2343  		"rb",
  2344  		defaultAlias+"/"+randomID,
  2345  	)
  2346  	errMSG, _ := parseSingleErrorMessageJSONOutput(out)
  2347  	validateErrorMSGValues(
  2348  		t,
  2349  		errMSG,
  2350  		"error",
  2351  		"Unable to validate",
  2352  		"does not exist",
  2353  	)
  2354  }
  2355  
  2356  func RemoveBucketWithNameTooLong(t *testing.T) {
  2357  	randomID := uuid.NewString()
  2358  	out, _ := RunMC(
  2359  		"rb",
  2360  		defaultAlias+"/"+randomID+randomID,
  2361  	)
  2362  	errMSG, _ := parseSingleErrorMessageJSONOutput(out)
  2363  	validateErrorMSGValues(
  2364  		t,
  2365  		errMSG,
  2366  		"error",
  2367  		"Unable to validate",
  2368  		"Bucket name cannot be longer than 63 characters",
  2369  	)
  2370  }
  2371  
  2372  func UploadToUnknownBucket(t *testing.T) {
  2373  	randomBucketID := uuid.NewString()
  2374  	parameters := append(
  2375  		[]string{},
  2376  		"cp",
  2377  		fileMap["1M"].diskFile.Name(),
  2378  		defaultAlias+"/"+randomBucketID+"-test-should-not-exist"+"/"+fileMap["1M"].fileNameWithoutPath,
  2379  	)
  2380  
  2381  	_, err := RunMC(parameters...)
  2382  	if err == nil {
  2383  		t.Fatalf("We should not have been able to upload to bucket: %s", randomBucketID)
  2384  	}
  2385  }
  2386  
  2387  func preRunCleanup() {
  2388  	for i := range tmpNameMap {
  2389  		_, _ = RunMC("rb", "--force", "--dangerous", defaultAlias+"/test-"+i)
  2390  	}
  2391  }
  2392  
  2393  func postRunCleanup(t *testing.T) {
  2394  	var err error
  2395  	var berr error
  2396  	var out string
  2397  
  2398  	err = os.RemoveAll(tempDir)
  2399  	if err != nil {
  2400  		fmt.Println(err)
  2401  	}
  2402  
  2403  	for _, v := range bucketList {
  2404  		out, berr = RunMC("rb", "--force", "--dangerous", v)
  2405  		if berr != nil {
  2406  			fmt.Printf("Unable to remove bucket (%s) err: %s //  out: %s", v, berr, out)
  2407  		}
  2408  	}
  2409  
  2410  	for _, v := range userList {
  2411  		_, _ = RunMC(
  2412  			"admin",
  2413  			"user",
  2414  			"remove",
  2415  			defaultAlias,
  2416  			v.Username,
  2417  		)
  2418  	}
  2419  
  2420  	fatalIfError(berr, t)
  2421  	fatalIfError(err, t)
  2422  }
  2423  
  2424  func validateFileLSInfo(t *testing.T, file *testFile) {
  2425  	if file.diskStat.Size() != int64(file.MinioLS.Size) {
  2426  		t.Fatalf(
  2427  			"File and minio object are not the same size - Object (%d) vs File (%d)",
  2428  			file.MinioLS.Size,
  2429  			file.diskStat.Size(),
  2430  		)
  2431  	}
  2432  	// if file.md5Sum != file.findOutput.Etag {
  2433  	// 	t.Fatalf("File and file.findOutput do not have the same md5Sum - Object (%s) vs File (%s)", file.findOutput.Etag, file.md5Sum)
  2434  	// }
  2435  	if file.storageClass != "" {
  2436  		if file.storageClass != file.MinioLS.StorageClass {
  2437  			t.Fatalf(
  2438  				"File and minio object do not have the same storage class - Object (%s) vs File (%s)",
  2439  				file.MinioLS.StorageClass,
  2440  				file.storageClass,
  2441  			)
  2442  		}
  2443  	} else {
  2444  		if file.MinioLS.StorageClass != "STANDARD" {
  2445  			t.Fatalf(
  2446  				"Minio object was expected to have storage class (STANDARD) but it was (%s)",
  2447  				file.MinioLS.StorageClass,
  2448  			)
  2449  		}
  2450  	}
  2451  }
  2452  
  2453  func validateObjectMetaData(t *testing.T, file *testFile) {
  2454  	for i, v := range file.metaData {
  2455  		found := false
  2456  
  2457  		for ii, vv := range file.MinioStat.Metadata {
  2458  			if metaPrefix+strings.Title(i) == ii {
  2459  				found = true
  2460  				if v != vv {
  2461  					fmt.Println("------------------------")
  2462  					fmt.Println("META CHECK")
  2463  					fmt.Println(file.MinioStat.Metadata)
  2464  					fmt.Println(file.metaData)
  2465  					fmt.Println("------------------------")
  2466  					t.Fatalf("Meta values are not the same v1(%s) v2(%s)", v, vv)
  2467  				}
  2468  			}
  2469  		}
  2470  
  2471  		if !found {
  2472  			fmt.Println("------------------------")
  2473  			fmt.Println("META CHECK")
  2474  			fmt.Println(file.MinioStat.Metadata)
  2475  			fmt.Println(file.metaData)
  2476  			fmt.Println("------------------------")
  2477  			t.Fatalf("Meta tag(%s) not found", i)
  2478  		}
  2479  
  2480  	}
  2481  }
  2482  
  2483  // func validateContentType(t *testing.T, file *testFile) {
  2484  // 	value, ok := file.MinioStat.Metadata["Content-Type"]
  2485  // 	if !ok {
  2486  // 		t.Fatalf("File (%s) did not have a content type", file.fileNameWithPrefix)
  2487  // 		return
  2488  // 	}
  2489  //
  2490  // 	contentType := mime.TypeByExtension(file.extension)
  2491  // 	if contentType != value {
  2492  // 		log.Println(file)
  2493  // 		log.Println(file.MinioLS)
  2494  // 		log.Println(file.extension)
  2495  // 		log.Println(file.MinioStat)
  2496  // 		t.Fatalf("Content types on file (%s) do not match, extension(%s) File(%s) MinIO object(%s)", file.fileNameWithPrefix, file.extension, contentType, file.MinioStat.Metadata["Content-Type"])
  2497  // 	}
  2498  // }
  2499  
  2500  func GetSource(skip int) (out string) {
  2501  	pc := make([]uintptr, 3) // at least 1 entry needed
  2502  	runtime.Callers(skip, pc)
  2503  	f := runtime.FuncForPC(pc[0])
  2504  	file, line := f.FileLine(pc[0])
  2505  	sn := strings.Split(f.Name(), ".")
  2506  	var name string
  2507  	if sn[len(sn)-1] == "func1" {
  2508  		name = sn[len(sn)-2]
  2509  	} else {
  2510  		name = sn[len(sn)-1]
  2511  	}
  2512  	out = file + ":" + fmt.Sprint(line) + ":" + name
  2513  	return
  2514  }
  2515  
  2516  func GetMD5Sum(data []byte) string {
  2517  	md5Writer := md5.New()
  2518  	md5Writer.Write(data)
  2519  	return fmt.Sprintf("%x", md5Writer.Sum(nil))
  2520  }
  2521  
  2522  func curlFatalIfNoErrorTag(msg string, t *testing.T) {
  2523  	if !strings.Contains(msg, "<Error>") {
  2524  		fmt.Println(failIndicator)
  2525  		fmt.Println(msg)
  2526  		t.Fatal(msg)
  2527  	}
  2528  }
  2529  
  2530  func fatalMsgOnly(msg string, t *testing.T) {
  2531  	fmt.Println(failIndicator)
  2532  	t.Fatal(msg)
  2533  }
  2534  
  2535  func fatalIfNoErrorWMsg(err error, msg string, t *testing.T) {
  2536  	if err == nil {
  2537  		fmt.Println(failIndicator)
  2538  		fmt.Println(msg)
  2539  		t.Fatal(err)
  2540  	}
  2541  }
  2542  
  2543  func fatalIfErrorWMsg(err error, msg string, t *testing.T) {
  2544  	if err != nil {
  2545  		fmt.Println(failIndicator)
  2546  		fmt.Println(msg)
  2547  		t.Fatal(err)
  2548  	}
  2549  }
  2550  
  2551  func fatalIfError(err error, t *testing.T) {
  2552  	if err != nil {
  2553  		fmt.Println(failIndicator)
  2554  		t.Fatal(err)
  2555  	}
  2556  }
  2557  
  2558  func parseFindJSONOutput(out string) (findList []*findMessage, err error) {
  2559  	findList = make([]*findMessage, 0)
  2560  	splitList := bytes.Split([]byte(out), []byte{10})
  2561  
  2562  	for _, v := range splitList {
  2563  		if len(v) < 1 {
  2564  			continue
  2565  		}
  2566  		line := new(findMessage)
  2567  		err = json.Unmarshal(v, line)
  2568  		if err != nil {
  2569  			return
  2570  		}
  2571  		findList = append(findList, line)
  2572  	}
  2573  
  2574  	if printRawOut {
  2575  		fmt.Println("FIND LIST ------------------------------")
  2576  		for _, v := range findList {
  2577  			fmt.Println(v)
  2578  		}
  2579  		fmt.Println(" ------------------------------")
  2580  	}
  2581  	return
  2582  }
  2583  
  2584  func parseDUJSONOutput(out string) (duList []duMessage, err error) {
  2585  	duList = make([]duMessage, 0)
  2586  	splitList := bytes.Split([]byte(out), []byte{10})
  2587  
  2588  	for _, v := range splitList {
  2589  		if len(v) < 1 {
  2590  			continue
  2591  		}
  2592  		line := duMessage{}
  2593  		err = json.Unmarshal(v, &line)
  2594  		if err != nil {
  2595  			return
  2596  		}
  2597  		duList = append(duList, line)
  2598  	}
  2599  
  2600  	if printRawOut {
  2601  		fmt.Println("DU LIST ------------------------------")
  2602  		for _, v := range duList {
  2603  			fmt.Println(v)
  2604  		}
  2605  		fmt.Println(" ------------------------------")
  2606  	}
  2607  	return
  2608  }
  2609  
  2610  func parseLSJSONOutput(out string) (lsList []contentMessage, err error) {
  2611  	lsList = make([]contentMessage, 0)
  2612  	splitList := bytes.Split([]byte(out), []byte{10})
  2613  
  2614  	for _, v := range splitList {
  2615  		if len(v) < 1 {
  2616  			continue
  2617  		}
  2618  		line := contentMessage{}
  2619  		err = json.Unmarshal(v, &line)
  2620  		if err != nil {
  2621  			return
  2622  		}
  2623  		lsList = append(lsList, line)
  2624  	}
  2625  
  2626  	if printRawOut {
  2627  		fmt.Println("LS LIST ------------------------------")
  2628  		for _, v := range lsList {
  2629  			fmt.Println(v)
  2630  		}
  2631  		fmt.Println(" ------------------------------")
  2632  	}
  2633  	return
  2634  }
  2635  
  2636  func parseFindSingleObjectJSONOutput(out string) (findInfo contentMessage, err error) {
  2637  	err = json.Unmarshal([]byte(out), &findInfo)
  2638  	if err != nil {
  2639  		return
  2640  	}
  2641  
  2642  	if printRawOut {
  2643  		fmt.Println("FIND SINGLE OBJECT ------------------------------")
  2644  		fmt.Println(findInfo)
  2645  		fmt.Println(" ------------------------------")
  2646  	}
  2647  	return
  2648  }
  2649  
  2650  func parseStatSingleObjectJSONOutput(out string) (stat statMessage, err error) {
  2651  	err = json.Unmarshal([]byte(out), &stat)
  2652  	if err != nil {
  2653  		return
  2654  	}
  2655  
  2656  	if printRawOut {
  2657  		fmt.Println("STAT ------------------------------")
  2658  		fmt.Println(stat)
  2659  		fmt.Println(" ------------------------------")
  2660  	}
  2661  	return
  2662  }
  2663  
  2664  // We have to wrap the error output because the console
  2665  // printing mechanism for json marshals into an anonymous
  2666  // object before printing, see cmd/error.go line 70
  2667  type errorMessageWrapper struct {
  2668  	Error  errorMessage `json:"error"`
  2669  	Status string       `json:"status"`
  2670  }
  2671  
  2672  func validateErrorMSGValues(
  2673  	t *testing.T,
  2674  	errMSG errorMessageWrapper,
  2675  	TypeToValidate string,
  2676  	MessageToValidate string,
  2677  	CauseToValidate string,
  2678  ) {
  2679  	if TypeToValidate != "" {
  2680  		if !strings.Contains(errMSG.Error.Type, TypeToValidate) {
  2681  			t.Fatalf(
  2682  				"Expected error.Error.Type to contain (%s) - but got (%s)",
  2683  				TypeToValidate,
  2684  				errMSG.Error.Type,
  2685  			)
  2686  		}
  2687  	}
  2688  	if MessageToValidate != "" {
  2689  		if !strings.Contains(errMSG.Error.Message, MessageToValidate) {
  2690  			t.Fatalf(
  2691  				"Expected error.Error.Message to contain (%s) - but got (%s)",
  2692  				MessageToValidate,
  2693  				errMSG.Error.Message,
  2694  			)
  2695  		}
  2696  	}
  2697  	if CauseToValidate != "" {
  2698  		if !strings.Contains(errMSG.Error.Cause.Message, CauseToValidate) {
  2699  			t.Fatalf(
  2700  				"Expected error.Error.Cause.Message to contain (%s) - but got (%s)",
  2701  				CauseToValidate,
  2702  				errMSG.Error.Cause.Message,
  2703  			)
  2704  		}
  2705  	}
  2706  }
  2707  
  2708  func parseUserMessageListOutput(out string) (users []*userMessage, err error) {
  2709  	users = make([]*userMessage, 0)
  2710  	splitList := bytes.Split([]byte(out), []byte{10})
  2711  	for _, v := range splitList {
  2712  		if len(v) < 1 {
  2713  			continue
  2714  		}
  2715  		msg := new(userMessage)
  2716  		err = json.Unmarshal(v, msg)
  2717  		if err != nil {
  2718  			return
  2719  		}
  2720  		users = append(users, msg)
  2721  	}
  2722  
  2723  	if printRawOut {
  2724  		fmt.Println("USER LIST ------------------------------")
  2725  		for _, v := range users {
  2726  			fmt.Println(v)
  2727  		}
  2728  		fmt.Println(" ------------------------------")
  2729  	}
  2730  
  2731  	return
  2732  }
  2733  
  2734  func parseShareMessageFromJSONOutput(out string) (share *shareMessage, err error) {
  2735  	share = new(shareMessage)
  2736  	err = json.Unmarshal([]byte(out), share)
  2737  	return
  2738  }
  2739  
  2740  func parseSingleErrorMessageJSONOutput(out string) (errMSG errorMessageWrapper, err error) {
  2741  	err = json.Unmarshal([]byte(out), &errMSG)
  2742  	if err != nil {
  2743  		return
  2744  	}
  2745  
  2746  	fmt.Println("ERROR ------------------------------")
  2747  	fmt.Println(errMSG)
  2748  	fmt.Println(" ------------------------------")
  2749  	return
  2750  }
  2751  
  2752  func parseSingleODMessageJSONOutput(out string) (odMSG odMessage, err error) {
  2753  	err = json.Unmarshal([]byte(out), &odMSG)
  2754  	if err != nil {
  2755  		return
  2756  	}
  2757  
  2758  	return
  2759  }
  2760  
  2761  func parseSingleAccountStatJSONOutput(out string) (stat accountStat, err error) {
  2762  	err = json.Unmarshal([]byte(out), &stat)
  2763  	if err != nil {
  2764  		return
  2765  	}
  2766  
  2767  	return
  2768  }
  2769  
  2770  func parseSingleCPMessageJSONOutput(out string) (cpMSG copyMessage, err error) {
  2771  	err = json.Unmarshal([]byte(out), &cpMSG)
  2772  	if err != nil {
  2773  		return
  2774  	}
  2775  
  2776  	return
  2777  }
  2778  
  2779  type newTestFile struct {
  2780  	tag          string // The tag used to identify the file inside the FileMap. This tag is also used in the objects name.
  2781  	prefix       string // Prefix for the object name ( not including the object name itself)
  2782  	extension    string
  2783  	storageClass string
  2784  	sizeInMBS    int
  2785  	// uploadShouldFail bool
  2786  	metaData map[string]string
  2787  	tags     map[string]string
  2788  
  2789  	addToGlobalFileMap bool
  2790  	// sub directory path to place the file in
  2791  	// tempDir+/+subDir
  2792  	subDir string
  2793  }
  2794  
  2795  type testFile struct {
  2796  	newTestFile
  2797  
  2798  	// File on disk
  2799  	diskFile *os.File
  2800  	// File info on disk
  2801  	diskStat os.FileInfo
  2802  	// md5sum at the time of creation
  2803  	md5Sum string
  2804  	// File name without full path
  2805  	fileNameWithoutPath string
  2806  	// File name with assigned prefix
  2807  	fileNameWithPrefix string
  2808  
  2809  	// These field are not automatically populated unless
  2810  	// the file is created at the initialization phase of
  2811  	// the test suite: testsThatDependOnOneAnother()
  2812  	// Minio mc stat output
  2813  	MinioStat statMessage
  2814  	// Minio mc ls output
  2815  	MinioLS contentMessage
  2816  }
  2817  
  2818  func (f *testFile) String() (out string) {
  2819  	out = fmt.Sprintf(
  2820  		"Size: %d || Name: %s || md5Sum: %s",
  2821  		f.diskStat.Size(),
  2822  		f.fileNameWithoutPath,
  2823  		f.md5Sum,
  2824  	)
  2825  	return
  2826  }
  2827  
  2828  func createFile(nf newTestFile) (newTestFile *testFile) {
  2829  	var newFile *os.File
  2830  	var err error
  2831  	if nf.subDir != "" {
  2832  
  2833  		err = os.MkdirAll(
  2834  			tempDir+string(os.PathSeparator)+nf.subDir,
  2835  			0o755)
  2836  		if err != nil {
  2837  			log.Println("Could not make additional dir:", err)
  2838  			os.Exit(1)
  2839  		}
  2840  
  2841  		newFile, err = os.CreateTemp(
  2842  			tempDir+string(os.PathSeparator)+nf.subDir,
  2843  			nf.tag+"-*"+nf.extension,
  2844  		)
  2845  
  2846  	} else {
  2847  		newFile, err = os.CreateTemp(tempDir, nf.tag+"-*"+nf.extension)
  2848  	}
  2849  
  2850  	if err != nil {
  2851  		log.Println("Could not make file:", err)
  2852  		os.Exit(1)
  2853  	}
  2854  
  2855  	md5Writer := md5.New()
  2856  	for i := 0; i < nf.sizeInMBS; i++ {
  2857  		n, err := newFile.Write(oneMBSlice[:])
  2858  		mn, merr := md5Writer.Write(oneMBSlice[:])
  2859  		if err != nil || merr != nil {
  2860  			log.Println(err)
  2861  			log.Println(merr)
  2862  			return nil
  2863  		}
  2864  		if n != len(oneMBSlice) {
  2865  			log.Println("Did not write 1MB to file")
  2866  			return nil
  2867  		}
  2868  		if mn != len(oneMBSlice) {
  2869  			log.Println("Did not write 1MB to md5sum writer")
  2870  			return nil
  2871  		}
  2872  	}
  2873  	splitName := strings.Split(newFile.Name(), string(os.PathSeparator))
  2874  	fileNameWithoutPath := splitName[len(splitName)-1]
  2875  	md5sum := fmt.Sprintf("%x", md5Writer.Sum(nil))
  2876  	stats, err := newFile.Stat()
  2877  	if err != nil {
  2878  		return nil
  2879  	}
  2880  	newTestFile = &testFile{
  2881  		md5Sum:              md5sum,
  2882  		fileNameWithoutPath: fileNameWithoutPath,
  2883  		diskFile:            newFile,
  2884  		diskStat:            stats,
  2885  	}
  2886  
  2887  	newTestFile.tag = nf.tag
  2888  	newTestFile.metaData = nf.metaData
  2889  	newTestFile.storageClass = nf.storageClass
  2890  	newTestFile.sizeInMBS = nf.sizeInMBS
  2891  	newTestFile.tags = nf.tags
  2892  	newTestFile.prefix = nf.prefix
  2893  	newTestFile.extension = nf.extension
  2894  
  2895  	if nf.prefix != "" {
  2896  		newTestFile.fileNameWithPrefix = nf.prefix + "/" + fileNameWithoutPath
  2897  	} else {
  2898  		newTestFile.fileNameWithPrefix = fileNameWithoutPath
  2899  	}
  2900  	if nf.addToGlobalFileMap {
  2901  		fileMap[nf.tag] = newTestFile
  2902  	}
  2903  	return newTestFile
  2904  }
  2905  
  2906  func BuildCLI() error {
  2907  	wd, _ := os.Getwd()
  2908  	fmt.Println("WORKING DIR:", wd)
  2909  	fmt.Println("go build -o", mcCmd, buildPath)
  2910  	os.Remove(mcCmd)
  2911  	out, err := exec.Command("go", "build", "-o", mcCmd, buildPath).CombinedOutput()
  2912  	if err != nil {
  2913  		log.Println("BUILD OUT:", out)
  2914  		log.Println(err)
  2915  		panic(err)
  2916  	}
  2917  	err = os.Chmod(mcCmd, 0o777)
  2918  	if err != nil {
  2919  		panic(err)
  2920  	}
  2921  	return nil
  2922  }
  2923  
  2924  func RunMC(parameters ...string) (out string, err error) {
  2925  	var outBytes []byte
  2926  	var outErr error
  2927  
  2928  	fmt.Println("")
  2929  	fmt.Println(time.Now().Format("2006-01-02T15:04:05.000"), "||", GetSource(3))
  2930  	fmt.Println(mcCmd, strings.Join(preCmdParameters, " "), strings.Join(parameters, " "))
  2931  
  2932  	outBytes, outErr = exec.Command(mcCmd, append(preCmdParameters, parameters...)...).CombinedOutput()
  2933  	if printRawOut {
  2934  		fmt.Println(string(outBytes))
  2935  	}
  2936  	out = string(outBytes)
  2937  	err = outErr
  2938  	return
  2939  }
  2940  
  2941  func RunCommand(cmd string, parameters ...string) (out string, err error) {
  2942  	fmt.Println("")
  2943  	fmt.Println(time.Now().Format("2006-01-02T15:04:05.000"), "||", GetSource(3))
  2944  	fmt.Println(cmd, strings.Join(parameters, " "))
  2945  	var outBytes []byte
  2946  	var outErr error
  2947  
  2948  	outBytes, outErr = exec.Command(cmd, parameters...).CombinedOutput()
  2949  	if printRawOut {
  2950  		fmt.Println(string(outBytes))
  2951  	}
  2952  	out = string(outBytes)
  2953  	err = outErr
  2954  	return
  2955  }