github.com/snowflakedb/gosnowflake@v1.9.0/file_transfer_agent_test.go (about)

     1  // Copyright (c) 2022 Snowflake Computing Inc. All rights reserved.
     2  
     3  package gosnowflake
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"net/url"
    12  	"os"
    13  	"path"
    14  	"path/filepath"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/aws/smithy-go"
    20  )
    21  
    22  type tcFilePath struct {
    23  	command string
    24  	path    string
    25  }
    26  
    27  func TestGetBucketAccelerateConfiguration(t *testing.T) {
    28  	if runningOnGithubAction() {
    29  		t.Skip("Should be run against an account in AWS EU North1 region.")
    30  	}
    31  	runSnowflakeConnTest(t, func(sct *SCTest) {
    32  		sfa := &snowflakeFileTransferAgent{
    33  			sc:          sct.sc,
    34  			commandType: uploadCommand,
    35  			srcFiles:    make([]string, 0),
    36  			data: &execResponseData{
    37  				SrcLocations: make([]string, 0),
    38  			},
    39  		}
    40  		if err := sfa.transferAccelerateConfig(); err != nil {
    41  			var ae smithy.APIError
    42  			if errors.As(err, &ae) {
    43  				if ae.ErrorCode() == "MethodNotAllowed" {
    44  					t.Fatalf("should have ignored 405 error: %v", err)
    45  				}
    46  			}
    47  		}
    48  	})
    49  }
    50  
    51  func TestUnitDownloadWithInvalidLocalPath(t *testing.T) {
    52  	tmpDir, err := os.MkdirTemp("", "data")
    53  	if err != nil {
    54  		t.Error(err)
    55  	}
    56  	defer os.RemoveAll(tmpDir)
    57  	testData := filepath.Join(tmpDir, "data.txt")
    58  	f, err := os.Create(testData)
    59  	if err != nil {
    60  		t.Error(err)
    61  	}
    62  	f.WriteString("test1,test2\ntest3,test4\n")
    63  	f.Close()
    64  
    65  	runDBTest(t, func(dbt *DBTest) {
    66  		if _, err = dbt.exec("use role sysadmin"); err != nil {
    67  			t.Skip("snowflake admin account not accessible")
    68  		}
    69  		dbt.mustExec("rm @~/test_get")
    70  		sqlText := fmt.Sprintf("put file://%v @~/test_get", testData)
    71  		sqlText = strings.ReplaceAll(sqlText, "\\", "\\\\")
    72  		dbt.mustExec(sqlText)
    73  
    74  		sqlText = fmt.Sprintf("get @~/test_get/data.txt file://%v\\get", tmpDir)
    75  		if _, err = dbt.query(sqlText); err == nil {
    76  			t.Fatalf("should return local path not directory error.")
    77  		}
    78  		dbt.mustExec("rm @~/test_get")
    79  	})
    80  }
    81  func TestUnitGetLocalFilePathFromCommand(t *testing.T) {
    82  	runSnowflakeConnTest(t, func(sct *SCTest) {
    83  		sfa := &snowflakeFileTransferAgent{
    84  			sc:          sct.sc,
    85  			commandType: uploadCommand,
    86  			srcFiles:    make([]string, 0),
    87  			data: &execResponseData{
    88  				SrcLocations: make([]string, 0),
    89  			},
    90  		}
    91  		testcases := []tcFilePath{
    92  			{"PUT file:///tmp/my_data_file.txt @~ overwrite=true", "/tmp/my_data_file.txt"},
    93  			{"PUT 'file:///tmp/my_data_file.txt' @~ overwrite=true", "/tmp/my_data_file.txt"},
    94  			{"PUT file:///tmp/sub_dir/my_data_file.txt\n @~ overwrite=true", "/tmp/sub_dir/my_data_file.txt"},
    95  			{"PUT file:///tmp/my_data_file.txt    @~ overwrite=true", "/tmp/my_data_file.txt"},
    96  			{"", ""},
    97  			{"PUT 'file2:///tmp/my_data_file.txt' @~ overwrite=true", ""},
    98  		}
    99  		for _, test := range testcases {
   100  			t.Run(test.command, func(t *testing.T) {
   101  				path := sfa.getLocalFilePathFromCommand(test.command)
   102  				if path != test.path {
   103  					t.Fatalf("unexpected file path. expected: %v, but got: %v", test.path, path)
   104  				}
   105  			})
   106  		}
   107  	})
   108  }
   109  
   110  func TestUnitProcessFileCompressionType(t *testing.T) {
   111  	runSnowflakeConnTest(t, func(sct *SCTest) {
   112  		sfa := &snowflakeFileTransferAgent{
   113  			sc:          sct.sc,
   114  			commandType: uploadCommand,
   115  			srcFiles:    make([]string, 0),
   116  		}
   117  		testcases := []struct {
   118  			srcCompression string
   119  		}{
   120  			{"none"},
   121  			{"auto_detect"},
   122  			{"gzip"},
   123  		}
   124  
   125  		for _, test := range testcases {
   126  			t.Run(test.srcCompression, func(t *testing.T) {
   127  				sfa.srcCompression = test.srcCompression
   128  				err := sfa.processFileCompressionType()
   129  				if err != nil {
   130  					t.Fatalf("failed to process file compression")
   131  				}
   132  			})
   133  		}
   134  
   135  		// test invalid compression type error
   136  		sfa.srcCompression = "gz"
   137  		data := &execResponseData{
   138  			SQLState: "S00087",
   139  			QueryID:  "01aa2e8b-0405-ab7c-0000-53b10632f626",
   140  		}
   141  		sfa.data = data
   142  		err := sfa.processFileCompressionType()
   143  		if err == nil {
   144  			t.Fatal("should have failed")
   145  		}
   146  		driverErr, ok := err.(*SnowflakeError)
   147  		if !ok {
   148  			t.Fatalf("should be snowflake error. err: %v", err)
   149  		}
   150  		if driverErr.Number != ErrCompressionNotSupported {
   151  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrCompressionNotSupported, driverErr.Number)
   152  		}
   153  	})
   154  }
   155  
   156  func TestParseCommandWithInvalidStageLocation(t *testing.T) {
   157  	runSnowflakeConnTest(t, func(sct *SCTest) {
   158  		sfa := &snowflakeFileTransferAgent{
   159  			sc:          sct.sc,
   160  			commandType: uploadCommand,
   161  			srcFiles:    make([]string, 0),
   162  			data: &execResponseData{
   163  				SrcLocations: make([]string, 0),
   164  			},
   165  		}
   166  
   167  		err := sfa.parseCommand()
   168  		if err == nil {
   169  			t.Fatal("should have raised an error")
   170  		}
   171  		driverErr, ok := err.(*SnowflakeError)
   172  		if !ok || driverErr.Number != ErrInvalidStageLocation {
   173  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrInvalidStageLocation, driverErr.Number)
   174  		}
   175  	})
   176  }
   177  
   178  func TestParseCommandEncryptionMaterialMismatchError(t *testing.T) {
   179  	runSnowflakeConnTest(t, func(sct *SCTest) {
   180  		mockEncMaterial1 := snowflakeFileEncryption{
   181  			QueryStageMasterKey: "abCdEFO0upIT36dAxGsa0w==",
   182  			QueryID:             "01abc874-0406-1bf0-0000-53b10668e056",
   183  			SMKID:               92019681909886,
   184  		}
   185  
   186  		mockEncMaterial2 := snowflakeFileEncryption{
   187  			QueryStageMasterKey: "abCdEFO0upIT36dAxGsa0w==",
   188  			QueryID:             "01abc874-0406-1bf0-0000-53b10668e056",
   189  			SMKID:               92019681909886,
   190  		}
   191  
   192  		sfa := &snowflakeFileTransferAgent{
   193  			sc:          sct.sc,
   194  			commandType: uploadCommand,
   195  			srcFiles:    make([]string, 0),
   196  			data: &execResponseData{
   197  				SrcLocations: []string{"/tmp/uploads"},
   198  				EncryptionMaterial: encryptionWrapper{
   199  					snowflakeFileEncryption: mockEncMaterial1,
   200  					EncryptionMaterials:     []snowflakeFileEncryption{mockEncMaterial1, mockEncMaterial2},
   201  				},
   202  			},
   203  		}
   204  
   205  		err := sfa.parseCommand()
   206  		if err == nil {
   207  			t.Fatal("should have raised an error")
   208  		}
   209  		driverErr, ok := err.(*SnowflakeError)
   210  		if !ok || driverErr.Number != ErrInternalNotMatchEncryptMaterial {
   211  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrInternalNotMatchEncryptMaterial, driverErr.Number)
   212  		}
   213  	})
   214  }
   215  
   216  func TestParseCommandInvalidStorageClientException(t *testing.T) {
   217  	runSnowflakeConnTest(t, func(sct *SCTest) {
   218  		tmpDir, err := os.MkdirTemp("", "abc")
   219  		if err != nil {
   220  			t.Error(err)
   221  		}
   222  		mockEncMaterial1 := snowflakeFileEncryption{
   223  			QueryStageMasterKey: "abCdEFO0upIT36dAxGsa0w==",
   224  			QueryID:             "01abc874-0406-1bf0-0000-53b10668e056",
   225  			SMKID:               92019681909886,
   226  		}
   227  
   228  		sfa := &snowflakeFileTransferAgent{
   229  			sc:          sct.sc,
   230  			commandType: uploadCommand,
   231  			srcFiles:    make([]string, 0),
   232  			data: &execResponseData{
   233  				SrcLocations:  []string{"/tmp/uploads"},
   234  				LocalLocation: tmpDir,
   235  				EncryptionMaterial: encryptionWrapper{
   236  					snowflakeFileEncryption: mockEncMaterial1,
   237  					EncryptionMaterials:     []snowflakeFileEncryption{mockEncMaterial1},
   238  				},
   239  			},
   240  		}
   241  
   242  		err = sfa.parseCommand()
   243  		if err == nil {
   244  			t.Fatal("should have raised an error")
   245  		}
   246  		driverErr, ok := err.(*SnowflakeError)
   247  		if !ok || driverErr.Number != ErrInvalidStageFs {
   248  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrInvalidStageFs, driverErr.Number)
   249  		}
   250  	})
   251  }
   252  
   253  func TestInitFileMetadataError(t *testing.T) {
   254  	runSnowflakeConnTest(t, func(sct *SCTest) {
   255  		sfa := &snowflakeFileTransferAgent{
   256  			sc:          sct.sc,
   257  			commandType: uploadCommand,
   258  			srcFiles:    []string{"fileDoesNotExist.txt"},
   259  			data: &execResponseData{
   260  				SQLState: "123456",
   261  				QueryID:  "01aa2e8b-0405-ab7c-0000-53b10632f626",
   262  			},
   263  		}
   264  
   265  		err := sfa.initFileMetadata()
   266  		if err == nil {
   267  			t.Fatal("should have raised an error")
   268  		}
   269  
   270  		driverErr, ok := err.(*SnowflakeError)
   271  		if !ok || driverErr.Number != ErrFileNotExists {
   272  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrFileNotExists, driverErr.Number)
   273  		}
   274  
   275  		tmpDir, err := os.MkdirTemp("", "data")
   276  		if err != nil {
   277  			t.Error(err)
   278  		}
   279  		defer os.RemoveAll(tmpDir)
   280  		sfa.srcFiles = []string{tmpDir}
   281  
   282  		err = sfa.initFileMetadata()
   283  		if err == nil {
   284  			t.Fatal("should have raised an error")
   285  		}
   286  
   287  		driverErr, ok = err.(*SnowflakeError)
   288  		if !ok || driverErr.Number != ErrFileNotExists {
   289  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrFileNotExists, driverErr.Number)
   290  		}
   291  	})
   292  }
   293  
   294  func TestUpdateMetadataWithPresignedUrl(t *testing.T) {
   295  	runSnowflakeConnTest(t, func(sct *SCTest) {
   296  		info := execResponseStageInfo{
   297  			Location:     "gcs-blob/storage/users/456/",
   298  			LocationType: "GCS",
   299  		}
   300  
   301  		dir, err := os.Getwd()
   302  		if err != nil {
   303  			t.Error(err)
   304  		}
   305  
   306  		testURL := "https://storage.google.com/gcs-blob/storage/users/456?Signature=testsignature123"
   307  
   308  		presignedURLMock := func(_ context.Context, _ *snowflakeRestful,
   309  			_ *url.Values, _ map[string]string, _ []byte, _ time.Duration,
   310  			requestID UUID, _ *Config) (*execResponse, error) {
   311  			// ensure the same requestID from context is used
   312  			if len(requestID) == 0 {
   313  				t.Fatal("requestID is empty")
   314  			}
   315  			dd := &execResponseData{
   316  				QueryID: "01aa2e8b-0405-ab7c-0000-53b10632f626",
   317  				Command: string(uploadCommand),
   318  				StageInfo: execResponseStageInfo{
   319  					LocationType: "GCS",
   320  					Location:     "gcspuscentral1-4506459564-stage/users/456",
   321  					Path:         "users/456",
   322  					Region:       "US_CENTRAL1",
   323  					PresignedURL: testURL,
   324  				},
   325  			}
   326  			return &execResponse{
   327  				Data:    *dd,
   328  				Message: "",
   329  				Code:    "0",
   330  				Success: true,
   331  			}, nil
   332  		}
   333  
   334  		gcsCli, err := new(snowflakeGcsClient).createClient(&info, false)
   335  		if err != nil {
   336  			t.Error(err)
   337  		}
   338  		uploadMeta := fileMetadata{
   339  			name:              "data1.txt.gz",
   340  			stageLocationType: "GCS",
   341  			noSleepingTime:    true,
   342  			client:            gcsCli,
   343  			sha256Digest:      "123456789abcdef",
   344  			stageInfo:         &info,
   345  			dstFileName:       "data1.txt.gz",
   346  			srcFileName:       path.Join(dir, "/test_data/data1.txt"),
   347  			overwrite:         true,
   348  			options: &SnowflakeFileTransferOptions{
   349  				MultiPartThreshold: dataSizeThreshold,
   350  			},
   351  		}
   352  
   353  		sct.sc.rest.FuncPostQuery = presignedURLMock
   354  		sfa := &snowflakeFileTransferAgent{
   355  			sc:                sct.sc,
   356  			commandType:       uploadCommand,
   357  			command:           "put file:///tmp/test_data/data1.txt @~",
   358  			stageLocationType: gcsClient,
   359  			fileMetadata:      []*fileMetadata{&uploadMeta},
   360  		}
   361  
   362  		err = sfa.updateFileMetadataWithPresignedURL()
   363  		if err != nil {
   364  			t.Error(err)
   365  		}
   366  		if testURL != sfa.fileMetadata[0].presignedURL.String() {
   367  			t.Fatalf("failed to update metadata with presigned url. expected: %v. got: %v", testURL, sfa.fileMetadata[0].presignedURL.String())
   368  		}
   369  	})
   370  }
   371  
   372  func TestUpdateMetadataWithPresignedUrlForDownload(t *testing.T) {
   373  	runSnowflakeConnTest(t, func(sct *SCTest) {
   374  		info := execResponseStageInfo{
   375  			Location:     "gcs-blob/storage/users/456/",
   376  			LocationType: "GCS",
   377  		}
   378  
   379  		dir, err := os.Getwd()
   380  		if err != nil {
   381  			t.Error(err)
   382  		}
   383  
   384  		testURL := "https://storage.google.com/gcs-blob/storage/users/456?Signature=testsignature123"
   385  
   386  		gcsCli, err := new(snowflakeGcsClient).createClient(&info, false)
   387  		if err != nil {
   388  			t.Error(err)
   389  		}
   390  		downloadMeta := fileMetadata{
   391  			name:              "data1.txt.gz",
   392  			stageLocationType: "GCS",
   393  			noSleepingTime:    true,
   394  			client:            gcsCli,
   395  			stageInfo:         &info,
   396  			dstFileName:       "data1.txt.gz",
   397  			overwrite:         true,
   398  			srcFileName:       "data1.txt.gz",
   399  			localLocation:     dir,
   400  		}
   401  
   402  		sfa := &snowflakeFileTransferAgent{
   403  			sc:                sct.sc,
   404  			commandType:       downloadCommand,
   405  			command:           "get @~/data1.txt.gz file:///tmp/testData",
   406  			stageLocationType: gcsClient,
   407  			fileMetadata:      []*fileMetadata{&downloadMeta},
   408  			presignedURLs:     []string{testURL},
   409  		}
   410  
   411  		err = sfa.updateFileMetadataWithPresignedURL()
   412  		if err != nil {
   413  			t.Error(err)
   414  		}
   415  		if testURL != sfa.fileMetadata[0].presignedURL.String() {
   416  			t.Fatalf("failed to update metadata with presigned url. expected: %v. got: %v", testURL, sfa.fileMetadata[0].presignedURL.String())
   417  		}
   418  	})
   419  }
   420  
   421  func TestUpdateMetadataWithPresignedUrlError(t *testing.T) {
   422  	runSnowflakeConnTest(t, func(sct *SCTest) {
   423  		sfa := &snowflakeFileTransferAgent{
   424  			sc:                sct.sc,
   425  			command:           "get @~/data1.txt.gz file:///tmp/testData",
   426  			stageLocationType: gcsClient,
   427  			data: &execResponseData{
   428  				SQLState: "123456",
   429  				QueryID:  "01aa2e8b-0405-ab7c-0000-53b10632f626",
   430  			},
   431  		}
   432  
   433  		err := sfa.updateFileMetadataWithPresignedURL()
   434  		if err == nil {
   435  			t.Fatal("should have raised an error")
   436  		}
   437  		driverErr, ok := err.(*SnowflakeError)
   438  		if !ok || driverErr.Number != ErrCommandNotRecognized {
   439  			t.Fatalf("unexpected error code. expected: %v, got: %v", ErrCommandNotRecognized, driverErr.Number)
   440  		}
   441  	})
   442  }
   443  
   444  func TestUploadWhenFilesystemReadOnlyError(t *testing.T) {
   445  	if isWindows {
   446  		t.Skip("permission model is different")
   447  	}
   448  
   449  	var err error
   450  	roPath := t.TempDir()
   451  	if err != nil {
   452  		t.Fatal(err)
   453  	}
   454  
   455  	// Set the temp directory to read only
   456  	err = os.Chmod(roPath, 0444)
   457  	if err != nil {
   458  		t.Fatal(err)
   459  	}
   460  
   461  	info := execResponseStageInfo{
   462  		Location:     "gcs-blob/storage/users/456/",
   463  		LocationType: "GCS",
   464  	}
   465  	dir, err := os.Getwd()
   466  	if err != nil {
   467  		t.Error(err)
   468  	}
   469  
   470  	// Make sure that the test uses read only directory
   471  	t.Setenv("TMPDIR", roPath)
   472  
   473  	uploadMeta := fileMetadata{
   474  		name:              "data1.txt.gz",
   475  		stageLocationType: "GCS",
   476  		noSleepingTime:    true,
   477  		client:            gcsClient,
   478  		sha256Digest:      "123456789abcdef",
   479  		stageInfo:         &info,
   480  		dstFileName:       "data1.txt.gz",
   481  		srcFileName:       path.Join(dir, "/test_data/data1.txt"),
   482  		overwrite:         true,
   483  		options: &SnowflakeFileTransferOptions{
   484  			MultiPartThreshold: dataSizeThreshold,
   485  		},
   486  	}
   487  
   488  	sfa := &snowflakeFileTransferAgent{
   489  		sc: &snowflakeConn{
   490  			cfg: &Config{},
   491  		},
   492  		commandType:       uploadCommand,
   493  		command:           "put file:///tmp/test_data/data1.txt @~",
   494  		stageLocationType: gcsClient,
   495  		fileMetadata:      []*fileMetadata{&uploadMeta},
   496  		parallel:          1,
   497  	}
   498  
   499  	err = sfa.uploadFilesParallel([]*fileMetadata{&uploadMeta})
   500  	if err == nil {
   501  		t.Fatal("should error when the filesystem is read only")
   502  	}
   503  	if !strings.Contains(err.Error(), "errors during file upload:\nmkdir") {
   504  		t.Fatalf("should error when creating the temporary directory. Instead errored with: %v", err)
   505  	}
   506  }
   507  
   508  func TestUnitUpdateProgess(t *testing.T) {
   509  	var b bytes.Buffer
   510  	buf := io.Writer(&b)
   511  	buf.Write([]byte("testing"))
   512  
   513  	spp := &snowflakeProgressPercentage{
   514  		filename:        "test.txt",
   515  		fileSize:        float64(1500),
   516  		outputStream:    &buf,
   517  		showProgressBar: true,
   518  		done:            false,
   519  	}
   520  
   521  	spp.call(0)
   522  	if spp.done != false {
   523  		t.Fatal("should not be done.")
   524  	}
   525  
   526  	if spp.seenSoFar != 0 {
   527  		t.Fatalf("expected seenSoFar to be 0 but was %v", spp.seenSoFar)
   528  	}
   529  
   530  	spp.call(1516)
   531  	if spp.done != true {
   532  		t.Fatal("should be done after updating progess")
   533  	}
   534  }
   535  
   536  func TestCustomTmpDirPath(t *testing.T) {
   537  	tmpDir, err := os.MkdirTemp("", "")
   538  	if err != nil {
   539  		t.Fatalf("cannot create temp directory: %v", err)
   540  	}
   541  	defer os.RemoveAll(tmpDir)
   542  	uploadFile := filepath.Join(tmpDir, "data.txt")
   543  	f, err := os.Create(uploadFile)
   544  	if err != nil {
   545  		t.Error(err)
   546  	}
   547  	f.WriteString("test1,test2\ntest3,test4\n")
   548  	f.Close()
   549  
   550  	uploadMeta := &fileMetadata{
   551  		name:              "data.txt.gz",
   552  		stageLocationType: "local",
   553  		noSleepingTime:    true,
   554  		client:            local,
   555  		sha256Digest:      "123456789abcdef",
   556  		stageInfo: &execResponseStageInfo{
   557  			Location:     tmpDir,
   558  			LocationType: "local",
   559  		},
   560  		dstFileName: "data.txt.gz",
   561  		srcFileName: uploadFile,
   562  		overwrite:   true,
   563  		options: &SnowflakeFileTransferOptions{
   564  			MultiPartThreshold: dataSizeThreshold,
   565  		},
   566  	}
   567  
   568  	downloadFile := filepath.Join(tmpDir, "download.txt")
   569  	downloadMeta := &fileMetadata{
   570  		name:              "data.txt.gz",
   571  		stageLocationType: "local",
   572  		noSleepingTime:    true,
   573  		client:            local,
   574  		sha256Digest:      "123456789abcdef",
   575  		stageInfo: &execResponseStageInfo{
   576  			Location:     tmpDir,
   577  			LocationType: "local",
   578  		},
   579  		srcFileName: "data.txt.gz",
   580  		dstFileName: downloadFile,
   581  		overwrite:   true,
   582  		options: &SnowflakeFileTransferOptions{
   583  			MultiPartThreshold: dataSizeThreshold,
   584  		},
   585  	}
   586  
   587  	sfa := snowflakeFileTransferAgent{
   588  		sc: &snowflakeConn{
   589  			cfg: &Config{
   590  				TmpDirPath: tmpDir,
   591  			},
   592  		},
   593  		stageLocationType: local,
   594  	}
   595  	_, err = sfa.uploadOneFile(uploadMeta)
   596  	if err != nil {
   597  		t.Fatal(err)
   598  	}
   599  	_, err = sfa.downloadOneFile(downloadMeta)
   600  	if err != nil {
   601  		t.Fatal(err)
   602  	}
   603  	defer os.Remove("download.txt")
   604  }
   605  
   606  func TestReadonlyTmpDirPathShouldFail(t *testing.T) {
   607  	if isWindows {
   608  		t.Skip("permission model is different")
   609  	}
   610  	tmpDir, err := os.MkdirTemp("", "")
   611  	if err != nil {
   612  		t.Fatalf("cannot create temp directory: %v", err)
   613  	}
   614  	defer os.RemoveAll(tmpDir)
   615  
   616  	uploadFile := filepath.Join(tmpDir, "data.txt")
   617  	f, err := os.Create(uploadFile)
   618  	if err != nil {
   619  		t.Error(err)
   620  	}
   621  	f.WriteString("test1,test2\ntest3,test4\n")
   622  	f.Close()
   623  
   624  	err = os.Chmod(tmpDir, 0400)
   625  	if err != nil {
   626  		t.Fatalf("cannot mark directory as readonly: %v", err)
   627  	}
   628  	defer os.Chmod(tmpDir, 0600)
   629  
   630  	uploadMeta := &fileMetadata{
   631  		name:              "data.txt.gz",
   632  		stageLocationType: "local",
   633  		noSleepingTime:    true,
   634  		client:            local,
   635  		sha256Digest:      "123456789abcdef",
   636  		stageInfo: &execResponseStageInfo{
   637  			Location:     tmpDir,
   638  			LocationType: "local",
   639  		},
   640  		dstFileName: "data.txt.gz",
   641  		srcFileName: uploadFile,
   642  		overwrite:   true,
   643  		options: &SnowflakeFileTransferOptions{
   644  			MultiPartThreshold: dataSizeThreshold,
   645  		},
   646  	}
   647  
   648  	sfa := snowflakeFileTransferAgent{
   649  		sc: &snowflakeConn{
   650  			cfg: &Config{
   651  				TmpDirPath: tmpDir,
   652  			},
   653  		},
   654  		stageLocationType: local,
   655  	}
   656  	_, err = sfa.uploadOneFile(uploadMeta)
   657  	if err == nil {
   658  		t.Fatalf("should not upload file as temporary directory is not readable")
   659  	}
   660  }
   661  
   662  func TestUploadDownloadOneFileRequireCompress(t *testing.T) {
   663  	testUploadDownloadOneFile(t, false)
   664  }
   665  
   666  func TestUploadDownloadOneFileRequireCompressStream(t *testing.T) {
   667  	testUploadDownloadOneFile(t, true)
   668  }
   669  
   670  func testUploadDownloadOneFile(t *testing.T, isStream bool) {
   671  	tmpDir, err := os.MkdirTemp("", "data")
   672  	if err != nil {
   673  		t.Fatalf("cannot create temp directory: %v", err)
   674  	}
   675  	defer os.RemoveAll(tmpDir)
   676  	uploadFile := filepath.Join(tmpDir, "data.txt")
   677  	f, err := os.Create(uploadFile)
   678  	if err != nil {
   679  		t.Error(err)
   680  	}
   681  	f.WriteString("test1,test2\ntest3,test4\n")
   682  	f.Close()
   683  
   684  	uploadMeta := &fileMetadata{
   685  		name:              "data.txt.gz",
   686  		stageLocationType: "local",
   687  		noSleepingTime:    true,
   688  		client:            local,
   689  		sha256Digest:      "123456789abcdef",
   690  		stageInfo: &execResponseStageInfo{
   691  			Location:     tmpDir,
   692  			LocationType: "local",
   693  		},
   694  		dstFileName: "data.txt.gz",
   695  		srcFileName: uploadFile,
   696  		overwrite:   true,
   697  		options: &SnowflakeFileTransferOptions{
   698  			MultiPartThreshold: dataSizeThreshold,
   699  		},
   700  		requireCompress: true,
   701  	}
   702  
   703  	downloadFile := filepath.Join(tmpDir, "download.txt")
   704  	downloadMeta := &fileMetadata{
   705  		name:              "data.txt.gz",
   706  		stageLocationType: "local",
   707  		noSleepingTime:    true,
   708  		client:            local,
   709  		sha256Digest:      "123456789abcdef",
   710  		stageInfo: &execResponseStageInfo{
   711  			Location:     tmpDir,
   712  			LocationType: "local",
   713  		},
   714  		srcFileName: "data.txt.gz",
   715  		dstFileName: downloadFile,
   716  		overwrite:   true,
   717  		options: &SnowflakeFileTransferOptions{
   718  			MultiPartThreshold: dataSizeThreshold,
   719  		},
   720  	}
   721  
   722  	sfa := snowflakeFileTransferAgent{
   723  		sc: &snowflakeConn{
   724  			cfg: &Config{
   725  				TmpDirPath: tmpDir,
   726  			},
   727  		},
   728  		stageLocationType: local,
   729  	}
   730  
   731  	if isStream {
   732  		fileStream, _ := os.Open(uploadFile)
   733  		ctx := WithFileStream(context.Background(), fileStream)
   734  		uploadMeta.srcStream = getFileStream(ctx)
   735  	}
   736  
   737  	_, err = sfa.uploadOneFile(uploadMeta)
   738  	if err != nil {
   739  		t.Fatal(err)
   740  	}
   741  	if uploadMeta.resStatus != uploaded {
   742  		t.Fatalf("failed to upload file")
   743  	}
   744  
   745  	_, err = sfa.downloadOneFile(downloadMeta)
   746  	if err != nil {
   747  		t.Fatal(err)
   748  	}
   749  	defer os.Remove("download.txt")
   750  	if downloadMeta.resStatus != downloaded {
   751  		t.Fatalf("failed to download file")
   752  	}
   753  }